Utilizzando SFINAE per rilevare POD-zione di un tipo in C ++
-
22-08-2019 - |
Domanda
Il titolo originale era qui Soluzione per SFINAE bug in VS2005 C ++
Questa è l'uso sperimentale di SFINAE per rendere l'equivalente per la classe template is_pod che esiste in TR1 (in VS2005 non c'è TR1 ancora). Esso dovrebbe avere il suo valore membro vero quando il parametro di modello è un tipo di POD (inclusi i tipi primitivi e le strutture fatte di loro) e false quando non è (come con i costruttori non banali).
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;
}
Il problema è, non solo VS 2005 non ha TR1, non si preoccupano il sindacato di cui sopra (che non dovrebbe essere valida quando il parametro modello non è un POD), così sia A che B restituire vero.
Grazie per le risposte postato qui sotto. Dopo aver letto con attenzione loro (e il codice) mi sono reso conto che quello che stavo cercando di fare è stato davvero un approccio sbagliato. L'idea era di combinare il comportamento SFINAE con un adattamento al modello must_be_pod (che ho trovato nel libro imperfetta C ++ , ma lo si può trovare in un altro posti, anche). In realtà, questo richiederebbe piuttosto un particolare insieme di regole per SFINAE, che non sono ciò che lo standard definisce, ovviamente. Questo non è un bug in VS, dopo tutto.
Soluzione
Il problema più grande con il vostro approccio è non fai SFINAE qui -. SFINAE si applica solo ai tipi di parametri e di ritorno Tipo qui
Tuttavia, di tutte le situazioni SFINAE nella norma, nessuno si applica alla vostra situazione. Sono
- array di vuoto, i riferimenti, le funzioni, o di dimensione non valida
- utente tipo che non è un tipo
- puntatori a riferimenti, i riferimenti ai riferimenti, riferimenti revocatorie
- puntatore a membro di un tipo non-class
- conversioni non valide di parametri di valore template
- tipi di funzione con argomenti di tipo void
- const / tipo di funzione volatile
Questo è probabilmente il motivo per cui nella documentazione Boost, c'è:
Senza un aiuto (come ancora non specificata) dal compilatore, ispod non sarà mai riferiscono che una classe o struct è un POD; questo è sempre sicuro, se, eventualmente, sub-ottimale. Attualmente (maggio 2005) solo Mwcw 9 e Visual C ++ 8 hanno il necessaria compilatore-_intrinsics.
Altri suggerimenti
Questo non funziona con VS2008 sia, ma ho il sospetto si sapeva anche questo. SFINAE è per dedurre argomenti di template per i parametri del modello; non si può davvero dedurre il tipo di cosa che rivela il costruttore-ness di un tipo, anche se è possibile creare un tipo che non è compatibile con un altro tipo (vale a dire, i sindacati non possono utilizzare non-POD).
In realtà, VS 2008 utilizza il supporto del compilatore per i tratti di implementare std::tr1::type_traits
.
Non sono sicuro circa il modo in cui si sta cercando di fare SFINAE qui, dal momento che is_pod<T>::test(...)
corrisponderà is_pod<T>::test(0)
troppo. Forse, se si utilizza un tipo diverso, invece di 'int' si otterrebbe una migliore corrispondenza:
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))};
};
Si potrebbe anche voler guardare Boost.Enable_i f per fare la tua SFINAE per te -. a meno che non si sta cercando di implementare la propria libreria o per qualche motivo