Usando SFINAE para detectar POD-dade de um tipo em C ++
-
22-08-2019 - |
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.
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