2012-07-03 8 views
16

Sto provando a implementare std::is_enum. Ecco il mio codice finora:implementazione isumen

template<typename T> 
struct is_enum { 
    static bool value; 
}; 

template<typename T> 
bool is_enum<T>::value = false; 

template<enum E> 
struct is_enum { 
    static bool value; 
}; 

template<enum E> 
bool is_enum<E>::value = true; 

Questo codice causa un errore. Più precisamente:

g++ -std=c++0x -Wall -o "enum2" "enum2.cpp" (in directory: /home/aristophanes/Desktop/C++) 
Compilation failed. 
enum2.cpp:11:15: error: use of enum ‘E’ without previous declaration 
enum2.cpp:3:10: error: template parameter ‘class T’ 
enum2.cpp:12:8: error: redeclared here as ‘int E’ 
enum2.cpp:16:15: error: use of enum ‘E’ without previous declaration 
enum2.cpp:17:14: error: ‘E’ was not declared in this scope 
enum2.cpp:17:15: error: template argument 1 is invalid 
enum2.cpp:17:18: error: template declaration of ‘bool value’ 

Qualcuno può spiegarmi dove faccio un errore? È colpa mia o del compilatore? Grazie in anticipo.

Modifica: se è completamente sbagliato, quindi come posso correggerlo?

Nota: sto usando g++ -o <file> <file>.cpp

+11

Sono abbastanza sicuro che 'is_enum', come molti altri tratti di tipo, non può essere implementato senza intrinseco del compilatore. – ildjarn

+0

[OT] In questo caso, un'alternativa migliore alle variabili statiche può essere _enums_ (come: 'enum {value = false};') – Gigi

+5

@Gigi: Questo è taggato 'C++ 11' - l'alternativa _best_ è quella eredita da 'std :: true_type',' std :: false_type', o 'std :: integral_constant <>'. : -] – ildjarn

risposta

13

Il modo migliore per implementare questo è usare il compilatore magico, e credo che molte implementazioni lo facciano.

Ad esempio, ecco implementazione ++ libc 's per gcc> = 4.3 e qualsiasi compilatore che __has_feature(is_enum)

template <class _Tp> struct _LIBCPP_VISIBLE is_enum 
    : public integral_constant<bool, __is_enum(_Tp)> {}; 



Per tutti gli altri compilatori libC++ fa:

template <class _Tp> struct _LIBCPP_VISIBLE is_enum 
    : public integral_constant<bool, !is_void<_Tp>::value    && 
            !is_integral<_Tp>::value   && 
            !is_floating_point<_Tp>::value && 
            !is_array<_Tp>::value   && 
            !is_pointer<_Tp>::value   && 
            !is_reference<_Tp>::value  && 
            !is_member_pointer<_Tp>::value && 
            !is_union<_Tp>::value   && 
            !is_class<_Tp>::value   && 
            !is_function<_Tp>::value   > {}; 

Alcuni di quegli altri tratti di tipo richiedono ancora la magia del compilatore. E.g. is_union. Tuttavia, questa condizione può essere riscritta in modo tale da non aver bisogno della magia del compilatore. Questo può essere fatto sostituendo gli assegni separati per sindacati e classi con un unico assegno per entrambi, come sottolinea Johannes Schaub.

1. Per quanto ne so solo clang implementa __has_feature, sfortunatamente. 2. È interessante notare che libC++ ha una versione di is_union<T> e is_class<T> che non utilizza i componenti intrinseci del compilatore, ma come risultato forniscono risultati errati per i tipi di unione. Ma i loro risultati errati sono complementari, quindi l'implementazione di fallback di libC++ di is_enum<T> fornisce risultati accurati.

+2

La tua risposta non è corretta. Nella definizione alternativa, è possibile sostituire '! Is_union <_Tp> &&! Is_class <_Tp>' da '! Is_union_or_class <_Tp>', che è piuttosto semplice da implementare senza il compilatore-intrinseco cercando di formare un puntatore membro e affidandosi a SFINAE. Tutti gli altri tipi di testine menzionati possono essere scritti anche senza supporto intrinseco. –

+0

@ JohannesSchaub-litb good catch – bames53

+0

@Johannes: Ah, "is_union_or_class' non mi è venuto in mente. Roba buona. – ildjarn

7

Questo

template<enum E> 

promesse che l'argomento modello è un valore di tipo enum E. L'argomento NON è di tipo (gli argomenti modello tipo vengono introdotti da typename o compatibilità con le versioni precedenti, class. Anche struct non è consentito). È proprio come dire

template<int i> 

tranne che non viene fornito alcun nome per la variabile.

Le cose vanno male da lì.

+0

C'è un modo per correggere il codice? –

+0

@RondogiannisAristophanes: No, è necessario un operatore incorporato nel compilatore, come ha detto ildjarn nei commenti. –

1

È problema è che

template<enum E> 

viene interpretato come parametro senza nome con tipo enum avanti dichiarato di nome E.
semanticamente uguale a

template<int> 

Basta sostituire int con enum E.