Pergunta

O título original aqui foi Solução para SFINAE bug no VS2005 C ++

Este é o uso experimental de SFINAE para fazer o equivalente para a classe de modelo is_pod que existe em TR1 (In VS2005 não há TR1 ainda). Ele deve ter sua valor membro verdadeiro quando o parâmetro do modelo é um tipo POD (incluindo tipos primitivos e estruturas feitas deles) e falsa quando não é (como com construtores não triviais).

template <typename T> class is_pod
{
  public:

    typedef char Yes;
    typedef struct {char a[2];} No;

    template <typename C> static Yes test(int)
    {
      union {T validPodType;} u;
    }
    template <typename C> static No test(...)
    {
    }
    enum {value = (sizeof(test<T>(0)) == sizeof(Yes))};
};

class NonPOD
{
  public:
    NonPod(const NonPod &);
    virtual ~NonPOD();
};

int main()
{
  bool a = is_pod<char>::value;
  bool b = is_pod<NonPOD>::value;
  if (a) 
    printf("char is POD\n");
  if (b)
    printf("NonPOD is POD ?!?!?\n");
  return 0;
}

O problema é, não só VS 2005 não tem TR1, não se preocupam com a união acima (que não deve ser válido quando o parâmetro do modelo não é um POD), de modo que tanto a como b avaliar a verdade.


Obrigado pelas respostas publicadas abaixo. Depois de ler cuidadosamente-los (e código) eu percebi que o que eu estava tentando fazer era realmente uma abordagem errada. A ideia era combinar comportamento SFINAE com uma adaptação ao modelo de must_be_pod (o que eu encontrei no livro Imperfect C ++ , mas ele pode ser encontrado em outros lugares, também). Na verdade, isso exigiria um conjunto muito especial de regras para SFINAE, que não são o que a norma define, obviamente. Isto não é realmente um bug no VS, depois de tudo.

Foi útil?

Solução

O maior problema com a sua abordagem é que você não faça SFINAE aqui -. SFINAE só se aplica aos tipos de parâmetros e tipo de retorno aqui

No entanto, de todas as situações SFINAE no padrão, nenhuma se aplica à sua situação. Eles são

  • matrizes de vazio, referências, funções, ou de tamanho inválido
  • membro do tipo que não é um tipo
  • ponteiros para referências, as referências a referências, as referências ao vazio
  • ponteiro para membro de um tipo não-class
  • conversões inválidas de parâmetros de valor template
  • tipos de função com argumentos de tipo void
  • const / tipo de função volátil

Isso é provavelmente porque na documentação Boost, existe:

Sem algum (ainda não especificada) ajuda do compilador, ispod nunca será relatam que uma classe ou struct é um POD; este é sempre seguro, se possivelmente sub-óptima. Actualmente (Maio de 2005), apenas MWCW 9 e Visual C ++ 8 tem a necessárias compilador de _intrinsics.

Outras dicas

Esta não funciona com VS2008 também, mas eu suspeito que você também sabia disso. SFINAE é para deduzir argumentos de modelo para parâmetros do modelo; você realmente não pode deduzir o tipo de algo que revela o construtor-ness de um tipo, mesmo que você pode criar um tipo que é incompatível com outro tipo (ou seja, os sindicatos não pode usar não-POD).

Na verdade, VS 2008 usa suporte de compilador para características de implementar std::tr1::type_traits.

Eu não tenho certeza sobre a maneira que você está tentando fazer SFINAE aqui, já que is_pod<T>::test(...) irá corresponder is_pod<T>::test(0) também. Talvez se você usar um tipo diferente, em vez de 'int' que você deseja obter uma melhor adequação:

template <typename T> class is_pod
{
  struct my_special_type { };
  public:
    typedef char Yes;
    typedef struct {char a[2];} No;

    template <typename C> static Yes test(my_special_type)
    {
      union {T validPodType;} u;
    }

    template <typename C> static No test(...)
    {
    }
    enum {value = (sizeof(test<T>(my_special_type())) == sizeof(Yes))};
};

Você também pode querer olhar em Boost.Enable_i f para fazer sua SFINAE para você -. a menos que você está tentando implementar sua própria biblioteca ou por algum motivo

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top