2011-01-16 3 views
3

Ich möchte einen Operator < < für alle Aufzählungen zu definieren, um den Wert zu cout und drucken, dass es eine Enumeration ist wie folgt:Wie kann man wissen, ob das Argument, das an die Funktion übergeben wird, eine Klasse, Union oder enum in C++ ist?

Code:

enum AnyEnum{A,B,C}; 
AnyEnum enm = A; 
cout << enm <<endl; 

Ausgang:

This is an enum which has a value equal to 0 

Ich kenne einen Weg, dies mit Boost-Bibliothek zu tun, indem Sie is_enum struct. Aber ich verstehe nicht, wie es funktioniert. Aus diesem Grund bin ich im Allgemeinen daran interessiert herauszufinden, ob es sich bei der Veriable um einen Klassentyp, einen Unionstyp oder eine enum (in der Kompilierungszeit) handelt.

Antwort

5

Bestimmung Klassentypen können Sie die Tatsache nutzen, dass das Mitglied Zeiger existieren

template<typename A, typename B> 
struct issame { }; 

template<typename A> 
struct issame<A, A> { typedef void type; }; 

template<typename> struct tovoid { typedef void type; }; 

template<typename T, typename = void> 
struct isclass { static bool const value = false; }; 

template<typename C> 
struct isclass<C, typename tovoid<int C::*>::type> { 
    static bool const value = true; 
}; 

Sie können nicht den Unterschied von einer Vereinigung erkennen und einer nicht gewerkschaftlich Klasse. Zumindest weiß ich nicht wie und Boost weiß es auch nicht.

Ich denke, Erkennung Enums könnte funktionieren, indem Sie sicherstellen, T ist keine Klasse, Funktion oder Integraltyp, und dann versuchen, einen integralen Typ zuweisen. Sie könnten

template<typename E, typename = void> 
struct isenum { 
    struct No { char x; }; 
    struct Yes { No n1; No n2; }; 

    struct nullsink {}; 
    static No checkI(nullsink*); // accept null pointer constants 
    static Yes checkI(...); 

    static Yes checkE(int); 
    static No checkE(...); 

    static bool const value = (sizeof(checkI(E())) == sizeof(Yes)) && 
          (sizeof(checkE(E())) == sizeof(Yes)); 
}; 

// class 
template<typename E> 
struct isenum<E, typename tovoid<int E::*>::type> { 
    static bool const value = false; 
}; 

// reference 
template<typename R> 
struct isenum<R&, void> { 
    static bool const value = false; 
}; 

// function (FuntionType() will error out). 
template<typename F> 
struct isenum<F, typename issame<void(F), void(F*)>::type> { 
    static bool const value = false; 
}; 

// array (ArrayType() will error out) 
template<typename E> 
struct isenum<E[], void> { 
    static bool const value = false; 
}; 
template<typename E, int N> 
struct isenum<E[N], void> { 
    static bool const value = false; 
}; 

Schnell & schmutzig Test (Arbeiten auf GCC/Klappern/comeau):

enum A { }; 
struct B { }; 
typedef int &C; 
typedef void D(); 
typedef int E; 
typedef long F; 
typedef int const G; 
typedef int H[1]; 

template<typename T, bool E> 
struct confirm { typedef char x[(T::value == E) ? 1 : -1]; }; 

int main() { 
    confirm< isenum<A>, true >(); 
    confirm< isenum<B>, false >(); 
    confirm< isenum<C>, false >(); 
    confirm< isenum<D>, false >(); 
    confirm< isenum<E>, false >(); 
    confirm< isenum<F>, false >(); 
    confirm< isenum<G>, false >(); 
    confirm< isenum<H>, false >(); 
} 
+0

Was bedeutet '(void) sizeof (x)'? : -/ – Nawaz

+0

@Nawaz: Es (Casting zu "void") ist nur um den zurückgegebenen Wert zu unterdrücken. :) –

+0

@Prasoon: hehe..das habe ich zuerst gedacht ... aber dann kam mir in den Sinn, dass, da es Johannes ist, er vielleicht etwas anderes meinte, was mir nicht bewusst ist. – Nawaz

-2

Es ist nicht möglich, den Variablentyp zum Zeitpunkt der Kompilierung zu kennen.

2

Ich bin interessiert, wie zu identifizieren, ob die veriable ist ein Klassentyp, Union-Typ oder eine enum (in Kompilierzeit).

boost::type_traits

Auch C++ TR1 hat <type_traits> Header bekam diese Funktionalität zu unterstützen. In C++ 0x wird alles viel besser.

Zum Beispiel der folgenden Maschinen nutzen SFINAE zu prüfen, ob das übergebene Argument ist ein Klassentyp:

template<typename T>struct Check_If_T_Is_Class_Type 
{ 
    template<typename C> static char func (char C::*p); 
    template<typename C> static long func (...); 
    enum{val = CHECKER(func,Check_If_T_Is_Class_Type)}; 
}; 

Die MACRO CHECKER ist

#define CHECKER(func_name,class_name) \ 
sizeof(class_name<T>::template func_name<T>(0)) == 1 

Um zu verstehen, wie type_traits arbeiten müssen Sie habe ein Grundwissen über Templates einschließlich template metaprogramming und SFINAE.

+0

Ja, das ist was ich meine. Bitte erklären Sie mir, wie diese Strukturen funktionieren. Zum Beispiel is_enum. – Narek

+0

@Narek: Sie müssen verstehen, wie Vorlagen arbeiten und Grundlagen in Bezug auf Vorlage Metaprogrammierung und SFINAE. –

+0

Ok, ich kenne einige Konzepte. SO Wie zeigt Ihr Beispiel, ob T eine Klasse oder nicht ist? – Narek

0

Dies wird in der Regel mit Compiler Haken getan. Der Compiler verfügt über spezielle Funktionen, die die Vorlage mit dem entsprechenden Wert "füllen" (zumindest in C++ 0x, wo type_traits standardisiert wurde). Zum Beispiel verwendet das Merkmal is_pod den __is_pod Compiler-Hook unter VC 10, um die entsprechenden Informationen zu erhalten.