2012-07-03 5 views
16

Ich versuche std::is_enum zu implementieren. Hier ist mein Code so weit:is_enum Implementierung

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; 

Dieser Code verursacht einen Fehler. Genauer gesagt:

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’ 

Kann mir jemand erklären, wo ich einen Fehler mache? Es ist mein oder der Compiler ist schuld? Danke im Voraus.

Edit: Wenn es komplett falsch ist, dann wie kann ich es korrigieren?

Hinweis: Ich verwende g++ -o <file> <file>.cpp

+11

Ich bin ziemlich sicher, dass 'is_enum', wie viele andere Typenmerkmale, nicht ohne Compiler intrinsics implementiert werden kann. – ildjarn

+0

[OT] In diesem Fall, kann eine bessere Alternative zu statischen Variablen sein _enums_ (wie: 'enum {value = false};') – Gigi

+5

@Gigi: Dies ist markiert 'C++ 11' - die _best_ Alternative ist zu erben von 'std :: true_type',' std :: false_type' oder 'std :: integral_constant <>'. : -] – ildjarn

Antwort

13

Der beste Weg, dies zu implementieren, ist Compiler Magie zu verwenden, und ich glaube, dass die meisten Implementierungen dies tun.

Zum Beispiel ist hier libC++ 's Implementierung für gcc> = 4,3 und eine beliebige Compiler, der __has_feature(is_enum)

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



Für alle anderen Compilern libC++ tut:

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   > {}; 

Einige diese anderen Typeigenschaften erfordern immer noch Compilermagie. z. is_union. Diese Bedingung kann jedoch so umgeschrieben werden, dass sie keine Compiler-Magie benötigt. Dies kann erreicht werden, indem die getrennten Schecks für Gewerkschaften und Klassen durch einen einzigen Scheck für beide ersetzt werden, wie Johannes Schaub betont.

1. Soweit ich weiß, nur clang __has_feature implementiert, leider.Es ist interessant, dass libC++ eine Version von is_union<T> und is_class<T> hat, die keine Compiler-Intrinsics verwenden, aber als Ergebnis falsche Ergebnisse für Union-Typen liefern. Aber ihre fehlerhaften Ergebnisse sind komplementär, so dass die Fallback-Implementierung von libC++ is_enum<T> genaue Ergebnisse liefert.

+2

Ihre Antwort ist falsch. In der alternativen Definition können Sie '! Is_union <_Tp> &&! Is_class <_Tp>' durch '! Is_union_or_class <_Tp>' ersetzen, was ziemlich einfach ohne Compiler-Intrinsics zu implementieren ist, indem Sie versuchen, einen Mitgliedszeiger zu bilden und SFINAE zu verwenden. Alle anderen dort genannten Typen können auch ohne Eigenunterstützung geschrieben werden. –

+0

@ JohannesSchaub-litb guter Fang – bames53

+0

@Johannes: Ah, 'is_union_or_class' ist mir nicht eingefallen. Gutes Zeug. – ildjarn

7

Diese

template<enum E> 

verspricht, dass das Template-Argument ein Wert ist vom Typ enum E. Das Argument ist KEIN Typ (Typvorlagenargumente werden von typename oder aus Gründen der Abwärtskompatibilität class eingeführt. Selbst struct ist nicht zulässig). Es ist nur so, als würde man sagen

template<int i> 

, außer dass kein Name für die Variable angegeben ist.

Dinge schief gehen von dort.

+0

Gibt es eine Möglichkeit, den Code zu korrigieren? –

+0

@RondogiannisAristophanes: Nein, Sie brauchen einen eingebauten Compiler-Operator, wie ildjarn in den Kommentaren sagte. –

1

Sie Problem ist, dass

template<enum E> 

als unbenannte Parameter mit Typ-vorwärts erklärt Enum E genannt interpretiert wird.
semantisch gleich

template<int> 

Substituieren Gerade int mit enum E.