Check für is member function pointer


  • Mod

    Nash26 schrieb:

    ist ja interesant, dein code funktioniert. Prima.

    template <typename T, typename C> struct is_mem_fun_ptr<T C::*> : is_function<T> {};
    

    Aber warum wird diese spezialisierung instanziert, obwohl ich ein ein type mit 10 parametern übergebe?

    Weil T selbst ein Funktionstyp sein kann. Und das passiert genau dann, wenn du das Template mit einem Zeiger auf non-const-non-volatile-Memberfunktion fütterst.
    Nimmst du in

    T (C::*)(...)
    

    den Deklarator ::* weg, bleibt ein Funktionstyp stehen. Leider können auf diese weise const und volatile Memberfunktionen nicht verarbeitet werden, weil Funktionstypen nicht qualifiziert sein dürfen (eine Einschränkung, für die mehr der Grund nie ganz klar geworden ist; dass Funktionen selbst nie qualifiziert sind, muss ja nichts mit dem Typen zu tun haben). Das führt zu der kuriosen Eigenschaft dass in z.B.

    T (C::*)(...)const
    

    nach Wegnahme des Deklarator ::* etwas steht, was kein (legaler) Typ ist. Da Deklaratoren aber eigentlich einen Typ aus einem anderen ableiten, ist das in meinem Augen seltsam.

    Nash26 schrieb:

    Das hier verstehe ich leider nicht:

    template <typename T> struct is_function : is_same<void(T),void(T*)> {};
    

    Der Test basiert auf den Besonderheiten die für die Deklarationen von Funktionsparametern gelten. Wird ein Funktionsparameter als Funktionstyp deklariert, so transformiert der Compiler das in eine Deklaration eines Funktionszeigers als Parameter (analog für Arrays, allerdings ist das Ergebnis der Transformation dort nicht ein Zeiger auf das Array sondern einer auf den Elementtyp). Es spielt also bei Funktionenparametern keine Rolle, ob ausdrücklich ein Zeiger deklariert wird, die Deklaration verweist trotzdem auf den selben Typ. Und das gilt so nur für Funktionstypen.

    Dein verlinkter Code nutzt übrigens die gleiche Eigenschaft, nur wird hier der sizeof-Überladungstrick angewendet.



  • ach du grüne neune und ich dachte ich wusste etwas über C++ und templates.

    Das hier ist eine Deklarator?

    ::*
    

    Was ist denn ein FunktionsType? Du meinst wohl eher wenn ich in

    T (C::*)(...)
    

    "C::" weglasse wird es ein function pointer?

    T (*)(...)
    

    Was meinst du mit

    qualifiziert

    in

    Funktionstypen nicht qualifiziert sein dürfen

    ?

    Es würde mir für das Verständnis extrem helfen wenn ich die einzelnen compiler schritte sehen könnte.

    Beispiel:

    struct Foo
    {
    void func(int,int) {}
    };
    template<class T>
    void call(T member)
    {
        bool result = is_mem_fun_ptr<T>::value;
    }
    
    call(&Foo::func);
    

    führt doch zu:

    //Schritt 1:
    
    template <typename T, typename C> struct is_mem_fun_ptr<void Foo::*> : is_function<void> {};
    
    //Schritt 2:
    
    template <typename T> struct is_function : is_same<void(void),void(void*)> {};
    

    mhm aber das macht doch keinen sinn...

    PS: Das code Beispiel aus dem Buch hat überhaupt nicht funktioniert, zumindest nicht mit VS2008



  • "Qualifiziert" bedeutet, dass hinter einer Memberfunktion ein const und/oder ein volatile steht. Das bezieht sich auf den this-Pointer, der ja ohne das C nicht mehr vorhanden ist.

    Bei Schritt 1 hast du dich geirrt:

    //Schritt 1:
    
    template <typename T, typename C> struct is_mem_fun_ptr<void(int, int) Foo::*> : is_function<void(int, int)> {};
    

    @SeppJ: Wenn ich dich richtig verstanden habe, dann ist ein Funktionstyp mit oder ohne Zeiger das gleiche. Warum verwendest du dann nicht is_same<T, T*>?


  • Mod

    Nash26 schrieb:

    ach du grüne neune und ich dachte ich wusste etwas über C++ und templates.

    Das hier ist eine Deklarator?

    ::*
    

    Was ist denn ein FunktionsType? Du meinst wohl eher wenn ich in

    T (C::*)(...)
    

    "C::" weglasse wird es ein function pointer?

    T (*)(...)
    

    Ein Zeiger auf Member wird deklariert durch
    nested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt D1
    also einem Bezeichner gefolgt vonm scope-Operator, gefolgt von einem Stern, gefolgt von etc., ich hätte also korrekterweise schreiben müssen:

    C::*
    

    wegzulassen.

    Nash26 schrieb:

    Was meinst du mit

    qualifiziert

    in

    Funktionstypen nicht qualifiziert sein dürfen

    ?

    Qualifikation bedeutet immer, dass zu einer Entität noch etwas dazu kommt, wenn nichts weiter dazu gesagt wird, bezieht sich das in der Regel darauf, das ein Typ oder ein Objekt zusätzlich als const und/oder volatile bestimmt (qualifiziert) wird. Im Zusammenhang mit Namelookup bezieht es sich auf Bezeichner, bei denen zusätzlich ein Scope angegeben wird. Die konkrete Bedeutung muss man jeweils dem Kontext entnehmen, aus Bequemlichkeit schreibe ich es nicht immer ausdrücklich hin.

    Nash26 schrieb:

    Es würde mir für das Verständnis extrem helfen wenn ich die einzelnen compiler schritte sehen könnte.

    Beispiel:

    struct Foo
    {
    void func(int,int) {}
    };
    template<class T>
    void call(T member)
    {
        bool result = is_mem_fun_ptr<T>::value;
    }
    
    call(&Foo::func);
    

    führt zu:T = void (Foo::*)(int, int)

    //Schritt 1:
    
    template <typename T, typename C> struct is_mem_fun_ptr<void (Foo::*)(int, int)> : is_function<void(int,int)> {};
    

    T = void(int,int), C = Foo

    //Schritt 2:
    
    template <typename T> struct is_function : is_same<void(void(int,int)),void(void(*)(int,int))> {};
    

    Auf beiden Seiten steht jeweils eine Funktion, die void zurückliefert, und einen Zeiger auf eine Funktion nimmt, welche ihrerseits void zurückgibt und 2 int-Parameter hat. Auf der linken Seite haben wir aber nicht ausdrücklich hingeschrieben, dess es ein Zeiger ist, diese Transformation nimmt der Compiler an dieser Stelle automatisch vor.

    Der obskure Fakt, dass man Funktionen so deklarieren kann, als ob sie einen Funktionsparameter hätten, ist als solches nichts, was man als normaler Programmierer beachten muss. Es taucht in C++ allerdings als Hindernis auf:
    falls du schon mal versucht hast, ein Objekt zu erstellen, dass mit einem default-konstruiertem anderen Objekt initialisiert werden sollte, bis du vielleicht darüber gestolpert:

    struct Foo { ... }; struct Bar { ... };
    ...
    Foo my_foo( Bar() ); // Funktionsdeklaration, keine Variablendefinition
    

    noch ein Grund, Initilisierung nicht gewohnheitsmäßig mit Klammern statt = durchzuführen... :p (eine Lösungsmöglichkeit besteht in einem zusätzlichen Klammerpaar um Bar() )



  • @camper: Ich habe jetzt deine Variante genommen und etwas veraendert. const/volatile Memberfunktionen funktionieren bei mir auch. Habe ich was uebersehen?

    template <bool B>
    struct bool_
    {
    	static bool const value = B;
    };
    
    typedef bool_<true> true_;
    typedef bool_<false> false_;
    
    template <typename T, typename U>
    struct is_same
    	: false_
    {};
    
    template <typename T>
    struct is_same<T, T>
    	: true_
    {};
    
    template <typename T>
    struct is_function
    	: is_same<void(T), void(T*)>
    {};
    
    template <typename T>
    struct is_member_function_pointer
    	: false_
    {};
    
    template <typename T, typename C>
    struct is_member_function_pointer<T C::*>
    	: is_function<T>
    {};
    
    ///////////////////
    
    #include <iostream>
    
    struct foo
    {};
    
    int main()
    {
    	std::cout << is_member_function_pointer<void (foo::*) (int, float)>::value << '\n';
    	std::cout << is_member_function_pointer<void (foo::*) (int, float) const>::value << '\n';
    	std::cout << is_member_function_pointer<void (foo::*) (int, float) volatile>::value << '\n';
    	std::cout << is_member_function_pointer<void (foo::*) (int, float) const volatile>::value << '\n';
    }
    

    http://ideone.com/HXYhj

    Edit: Mir faellt gerade auf, ich habe genau das gleiche wie du, nur ohne die Checks. Hab mir deinen Code nicht so genau angesehen 😃
    Trotzdem funktionierts auch mit const/volatile Memberfunktionen.


  • Mod

    Kellerautomat schrieb:

    Habe ich was uebersehen?

    Nein, scheint als bin ich hier einem Irrtum aufgessen.
    Es ist ist nicht möglich einen bereits bestehenden Funktionstyp mit cv-Qualifikation zu versehen, als Teil des Funktionstyp existiert die Qualifikation aber durchaus:

    typedef void f();
    typedef void g() const; // ältere Compiler werden das u.U. verweigern
    typedef const f h; // const wird ignoriert
    
    struct foo
    {
        f fun;  // deklariert void foo::fun()
        g fun;  // deklariert void foo::fun() const
        h fun;  // Fehler: Redeklaration von void foo::fun()
    };
    

    Umso besser: dann gibt es doch eine schöne Lösung auch in C++03.

    wenn ich

    template <bool b> struct bool_ { static const bool value = b; };
    typedef bool_<false> false_type;
    typedef bool_<true> true_type;
    
    template <typename T, typename U> struct is_same : false_type {};
    template <typename T> struct is_same<T, T> : true_type {};
    
    template <typename T> struct is_function : is_same<void(T),void(T*)> {};
    template <> struct is_function<const void> : false_type {};
    template <> struct is_function<volatile void> : false_type {};
    template <> struct is_function<const volatile void> : false_type {};
    template <typename T> struct is_function<T&> : false_type {};
    
    template <typename T> struct is_mem_fun_ptr : false_type {};
    template <typename T, typename C> struct is_mem_fun_ptr<T C::*> : is_function<T> {};
    
    struct Foo { void f(); void g() const; };
    
    template <typename T>
    void foo(T)
    {
        int dummy[is_mem_fun_ptr<T>::value];
    }
    
    int main()
    {
        foo(&Foo::f);
        foo(&Foo::g);
    }
    

    durch Online-Comeau C++ jage, gibt es Fehler. g++4.6 und clang sind damit zufrieden. Evtl. sollte man noch ältere Versionen von g++ und Visual C++ testen. Mir ist allerdings auch nicht bewusst, dass es hier eine Änderung in C++11 gegeben hätte. Ich bin allerdings auch ziemlich sicher, dass das früher nicht so funktioniert hat.



  • Also in VS2008 wird mit eurem code eine const member funktion nicht erkannt.
    Kann man noch irgendwo eine Spezialisierung einbauen, so das es funktioniert?

    Das der compiler das so hier auflöst hätte ich nicht gedacht.

    template <typename T, typename C> struct is_mem_fun_ptr<void (Foo::*)(int, int)> : is_function<void(int,int)> {};
    

    Mit ist leider immer noch einiges nicht klar:

    template <typename T, typename C> struct is_mem_fun_ptr<T C::*> : is_function<T> {};
    

    Für welchen Typ T wird dieses template instanziert, obwohl es keine member function ist?
    Durch T C::* kann es doch eigentlich nur für member functions aufgerufen werden.

    So das dann der nachfolgende Test mit is_function überhaupt nocht sinn macht.

    jetzt zu dem Konstrukt:

    template <typename T> struct is_function : is_same<void(void(int,int)),void(void(*)(int,int))> {};
    

    Auf der linken Seite deklarierst du einen Funktionszeiger, dieser wird durch den compiler nochmal 😕 zu einem Funktionszeiger transformiert? Auf der rechten Seite machen wir das manuell. Ist das so korrekt?

    PS: wo lernt man solche Tricks mit

    is_same<void(T),void(T*)> {};

    ?
    Also das wäre mit nicht im traum eingefallen.



  • Nash26 schrieb:

    template <typename T, typename C> struct is_mem_fun_ptr<T C::*> : is_function<T> {};
    

    Für welchen Typ T wird dieses template instanziert, obwohl es keine member function ist?

    Wenn der Parameter nicht auf diese Spezialisierung passt, wird das Default-Template genommen:

    template <typename T> struct is_mem_fun_ptr : false_type {};
    


  • @wxSkip
    das heißt also ich kann direkt

    template <typename T, typename C> struct is_mem_fun_ptr<T C::*> : true_type {};
    

    schreiben?



  • Nash26 schrieb:

    @wxSkip
    das heißt also ich kann direkt

    template <typename T, typename C> struct is_mem_fun_ptr<T C::*> : true_type {};
    

    schreiben?

    Nein. Es gibt auch Nicht-Memberfunktions-Typen, die auf diese Spezialisierung passen. Und zwar sind das die relativ unbekannten Zeiger auf Member. Wenn du eine Klasse mit verschiedenen Variablen hast, kannst du einen Zeiger auf eine Klassenvariable holen, der praktisch die interne Position in der Klasse speichert. Wenn du dann noch ein konkretes Objekt hast, kannst du mit diesem Zeiger auf die Variable dieses Objektes zugreifen.


  • Mod

    Nash26 schrieb:

    jetzt zu dem Konstrukt:

    template <typename T> struct is_function : is_same<void(void(int,int)),void(void(*)(int,int))> {};
    

    Auf der linken Seite deklarierst du einen Funktionszeiger, dieser wird durch den compiler nochmal 😕 zu einem Funktionszeiger transformiert? Auf der rechten Seite machen wir das manuell. Ist das so korrekt?

    Links wird ein Funktionstyp deklariert, rechts wird ein Funktionstyp deklariert. Beiden Typen haben ihrerseits einen Funktionszeiger als Parametertyp.

    Nash26 schrieb:

    PS: wo lernt man solche Tricks mit

    is_same<void(T),void(T*)> {};

    ?
    Also das wäre mit nicht im traum eingefallen.

    Den Trick als solchen habe ich mir on-the-fly beim Schreiben ausgedacht. Den zugrunde liegenden Mechanismus lernt man irgendwann nebenbei kennen, wenn es um etwas ganz anderes geht.



  • @camper
    tja bleibt nur noch die Frage warum es mit VS2008 nicht mit const methoden klappt.
    Hast du einen workaround dafür?



  • ich bekomme es einfach nicht hin:

    template <typename T, typename C> struct is_mem_fun_ptr<T const C::*> : is_function<T> {};
    

    wenn ich das template mit einer const member function aufrufe wird sofort:

    template <typename T> struct is_mem_fun_ptr : false_type {};
    

    instanziiert

    auch den const qualifier zu entfernen klappt nicht.


  • Mod

    Nash26 schrieb:

    @camper
    tja bleibt nur noch die Frage warum es mit VS2008 nicht mit const methoden klappt.
    Hast du einen workaround dafür?

    Nein. Es gilt dann einfach das, was ich zuerst gesagt habe.

    Nash26 schrieb:

    ich bekomme es einfach nicht hin:

    template <typename T, typename C> struct is_mem_fun_ptr<T const C::*> : is_function<T> {};
    

    wenn ich das template mit einer const member function aufrufe wird sofort:

    template <typename T> struct is_mem_fun_ptr : false_type {};
    

    instanziiert

    auch den const qualifier zu entfernen klappt nicht.

    Das ist kein Wunder.
    Einen const/volatile-Qualifizierer zu einem Funktionstyp hinzuzufügen macht daraus gerade keinen const/volatile-Funktionstyp, je nach Kontext ist es schlicht illegal oder wird ignoriert.

    Die Spezialisierung

    template <typename T, typename C> struct is_mem_fun_ptr<T const C::*> : is_function<T> {};
    

    würde folglich nur für Zeiger auf konstante Member (also vor allem keine Memberfunktionen) genutzt werden.

    boost.type_traits hat bereits eine portable Lösung. Ich kann keine Bessere anbieten.



  • du hattest geschrieben

    Das Testen auf non-const-non-volatile-Memberfunktionszeiger ist einfach. Schwierigkeiten machen nur const,volatile und const volatile-Memberfunktionen:

    das heißt also, es gibt für VS2008 nur die Möglichkeit auf viele Spezialiserungen zu testen? Korrekt?


  • Mod

    Nash26 schrieb:

    du hattest geschrieben

    Das Testen auf non-const-non-volatile-Memberfunktionszeiger ist einfach. Schwierigkeiten machen nur const,volatile und const volatile-Memberfunktionen:

    das heißt also, es gibt für VS2008 nur die Möglichkeit auf viele Spezialiserungen zu testen? Korrekt?

    Das, oder Ausschlussverfahren

    #include <cstddef>
    
    template <bool b> struct bool_ { static const bool value = b; };
    template <typename T> struct not_ { static const bool value = !T::value; };
    typedef bool_<true> true_type;
    typedef bool_<false> false_type;
    
    template <typename T> struct identity { typedef T type; };
    
    // is_same
    template <typename T, typename U> struct is_same : false_type {};
    template <typename T> struct is_same<T, T> : true_type {};
    
    // add_reference
    template <typename T> struct add_reference : identity<T&> {};
    template <typename T> struct add_reference<T&> : identity<T&> {};
    
    // remove_reference (funktioniert auch mit rvalue-Referenzen)
    template <typename T> struct remove_reference : remove_reference<typename add_reference<T>::type> {};
    template <typename T> struct remove_reference<T&> : identity<T> {};
    
    // is_reference (funktioniert auch mit rvalue-Referenzen)
    template <typename T> struct is_reference : not_<is_same<T, typename remove_reference<typename add_reference<T>::type>::type> > {};
    
    // is_pointer
    template <typename T> struct is_pointer : false_type {};
    template <typename T> struct is_pointer<T*> : true_type {};
    
    // is_class (class/struct/union)
    template <typename T> struct is_class
    {
        typedef char& yes_type;
        typedef char (&no_type)[2];
        template <typename U> static no_type test(...);
        template <typename U> static yes_type test(int U::*);
        static const bool value = sizeof test<T>(0) == sizeof(yes_type);
    };
    
    // is_array
    template <typename T> struct is_array : false_type {};
    template <typename T> struct is_array<T[]> : true_type {};
    template <typename T, std::size_t N> struct is_array<T[N]> : true_type {};
    
    // is_void
    template <typename T> struct is_void : false_type {};
    template <> struct is_void<void> : true_type {};
    template <> struct is_void<const void> : true_type {};
    template <> struct is_void<volatile void> : true_type {};
    template <> struct is_void<const volatile void> : true_type {};
    
    // is_function
    template <typename T, bool = !is_void<T>::value && !is_reference<T>::value> struct is_function : is_same<void(T),void(T*)> {};
    template <typename T> struct is_function<T, false> : false_type {};
    
    // is_convertible
    template <typename T, typename U> struct is_convertible
    {
        static typename add_reference<T>::type makeT();
        typedef char& yes_type;
        typedef char (&no_type)[2];
        static no_type test(...);
        static yes_type test(U);
        static const bool value = sizeof test(makeT()) == sizeof(yes_type);
    };
    
    // is_convertible_static
    template <typename T, typename U> struct is_convertible_static
    {
        static typename add_reference<T>::type makeT();
        typedef char& yes_type;
        typedef char (&no_type)[2];
        template <typename V> static no_type test(...);
        template <typename V> static yes_type test(char(*)[sizeof(static_cast<V>(makeT()))]);
        static const bool value = sizeof test<U>(0) == sizeof(yes_type);
    };
    
    // is_fundamental_or_enum (including scoped enums)
    template <typename T> struct is_fundamental_or_enum : bool_<is_void<T>::value || ( !is_class<T>::value && !is_reference<T>::value && is_convertible_static<T, int>::value )> {};
    
    // is_mem_data_ptr
    template <typename T> struct is_mem_data_ptr : false_type {};
    template <typename T, typename C> struct is_mem_data_ptr<T C::*> : not_<is_function<T> > {};
    
    // is_mem_fun_ptr
    template <typename T> struct is_mem_fun_ptr : bool_<!is_fundamental_or_enum<T>::value && !is_class<T>::value && !is_pointer<T>::value && !is_reference<T>::value
                                                        && !is_function<T>::value && !is_array<T>::value && !is_mem_data_ptr<T>::value> {};
    
    #include <iostream>
    
    enum A { a, b, c };
    enum class B { d, e, f };
    struct C {};
    union D {};
    
    int main()
    {
        using std::cout;
        cout << "\t\t\tint\tint&\tint&&\tint[6]\tint*\tint()\tint(*)();int(&)();enum A;ec B\tstructC\tunionD\tint D::*;int(D::*)();int(D::*)const\n";
        cout << "is_reference\t" << '\t';
        cout << is_reference<int>::value << '\t';
        cout << is_reference<int&>::value << '\t';
        cout << is_reference<int&&>::value << '\t';
        cout << is_reference<int[6]>::value << '\t';
        cout << is_reference<int*>::value << '\t';
        cout << is_reference<int()>::value << '\t';
        cout << is_reference<int(*)()>::value << '\t';
        cout << is_reference<int(&)()>::value << '\t';
        cout << is_reference<A>::value << '\t';
        cout << is_reference<B>::value << '\t';
        cout << is_reference<C>::value << '\t';
        cout << is_reference<D>::value << '\t';
        cout << is_reference<int D::*>::value << '\t';
        cout << is_reference<int (D::*)()>::value << '\t';
        cout << is_reference<int (D::*)()const>::value << '\n';
    
        cout << "is_array\t" << '\t';
        cout << is_array<int>::value << '\t';
        cout << is_array<int&>::value << '\t';
        cout << is_array<int&&>::value << '\t';
        cout << is_array<int[6]>::value << '\t';
        cout << is_array<int*>::value << '\t';
        cout << is_array<int()>::value << '\t';
        cout << is_array<int(*)()>::value << '\t';
        cout << is_array<int(&)()>::value << '\t';
        cout << is_array<A>::value << '\t';
        cout << is_array<B>::value << '\t';
        cout << is_array<C>::value << '\t';
        cout << is_array<D>::value << '\t';
        cout << is_array<int D::*>::value << '\t';
        cout << is_array<int (D::*)()>::value << '\t';
        cout << is_array<int (D::*)()const>::value << '\n';
    
        cout << "is_pointer\t" << '\t';
        cout << is_pointer<int>::value << '\t';
        cout << is_pointer<int&>::value << '\t';
        cout << is_pointer<int&&>::value << '\t';
        cout << is_pointer<int[6]>::value << '\t';
        cout << is_pointer<int*>::value << '\t';
        cout << is_pointer<int()>::value << '\t';
        cout << is_pointer<int(*)()>::value << '\t';
        cout << is_pointer<int(&)()>::value << '\t';
        cout << is_pointer<A>::value << '\t';
        cout << is_pointer<B>::value << '\t';
        cout << is_pointer<C>::value << '\t';
        cout << is_pointer<D>::value << '\t';
        cout << is_pointer<int D::*>::value << '\t';
        cout << is_pointer<int (D::*)()>::value << '\t';
        cout << is_pointer<int (D::*)()const>::value << '\n';
    
        cout << "is_function\t" << '\t';
        cout << is_function<int>::value << '\t';
        cout << is_function<int&>::value << '\t';
        cout << is_function<int&&>::value << '\t';
        cout << is_function<int[6]>::value << '\t';
        cout << is_function<int*>::value << '\t';
        cout << is_function<int()>::value << '\t';
        cout << is_function<int(*)()>::value << '\t';
        cout << is_function<int(&)()>::value << '\t';
        cout << is_function<A>::value << '\t';
        cout << is_function<B>::value << '\t';
        cout << is_function<C>::value << '\t';
        cout << is_function<D>::value << '\t';
        cout << is_function<int D::*>::value << '\t';
        cout << is_function<int (D::*)()>::value << '\t';
        cout << is_function<int (D::*)()const>::value << '\n';
    
        cout << "is_class\t" << '\t';
        cout << is_class<int>::value << '\t';
        cout << is_class<int&>::value << '\t';
        cout << is_class<int&&>::value << '\t';
        cout << is_class<int[6]>::value << '\t';
        cout << is_class<int*>::value << '\t';
        cout << is_class<int()>::value << '\t';
        cout << is_class<int(*)()>::value << '\t';
        cout << is_class<int(&)()>::value << '\t';
        cout << is_class<A>::value << '\t';
        cout << is_class<B>::value << '\t';
        cout << is_class<C>::value << '\t';
        cout << is_class<D>::value << '\t';
        cout << is_class<int D::*>::value << '\t';
        cout << is_class<int (D::*)()>::value << '\t';
        cout << is_class<int (D::*)()const>::value << '\n';
    
        cout << "is_fund_or_enum\t" << '\t';
        cout << is_fundamental_or_enum<int>::value << '\t';
        cout << is_fundamental_or_enum<int&>::value << '\t';
        cout << is_fundamental_or_enum<int&&>::value << '\t';
        cout << is_fundamental_or_enum<int[6]>::value << '\t';
        cout << is_fundamental_or_enum<int*>::value << '\t';
        cout << is_fundamental_or_enum<int()>::value << '\t';
        cout << is_fundamental_or_enum<int(*)()>::value << '\t';
        cout << is_fundamental_or_enum<int(&)()>::value << '\t';
        cout << is_fundamental_or_enum<A>::value << '\t';
        cout << is_fundamental_or_enum<B>::value << '\t';
        cout << is_fundamental_or_enum<C>::value << '\t';
        cout << is_fundamental_or_enum<D>::value << '\t';
        cout << is_fundamental_or_enum<int D::*>::value << '\t';
        cout << is_fundamental_or_enum<int (D::*)()>::value << '\t';
        cout << is_fundamental_or_enum<int (D::*)()const>::value << '\n';
    
        cout << "is_mem_data_ptr\t" << '\t';
        cout << is_mem_data_ptr<int>::value << '\t';
        cout << is_mem_data_ptr<int&>::value << '\t';
        cout << is_mem_data_ptr<int&&>::value << '\t';
        cout << is_mem_data_ptr<int[6]>::value << '\t';
        cout << is_mem_data_ptr<int*>::value << '\t';
        cout << is_mem_data_ptr<int()>::value << '\t';
        cout << is_mem_data_ptr<int(*)()>::value << '\t';
        cout << is_mem_data_ptr<int(&)()>::value << '\t';
        cout << is_mem_data_ptr<A>::value << '\t';
        cout << is_mem_data_ptr<B>::value << '\t';
        cout << is_mem_data_ptr<C>::value << '\t';
        cout << is_mem_data_ptr<D>::value << '\t';
        cout << is_mem_data_ptr<int D::*>::value << '\t';
        cout << is_mem_data_ptr<int (D::*)()>::value << '\t';
        cout << is_mem_data_ptr<int (D::*)()const>::value << '\n';
    
        cout << "is_mem_fun_ptr\t" << '\t';
        cout << is_mem_fun_ptr<int>::value << '\t';
        cout << is_mem_fun_ptr<int&>::value << '\t';
        cout << is_mem_fun_ptr<int&&>::value << '\t';
        cout << is_mem_fun_ptr<int[6]>::value << '\t';
        cout << is_mem_fun_ptr<int*>::value << '\t';
        cout << is_mem_fun_ptr<int()>::value << '\t';
        cout << is_mem_fun_ptr<int(*)()>::value << '\t';
        cout << is_mem_fun_ptr<int(&)()>::value << '\t';
        cout << is_mem_fun_ptr<A>::value << '\t';
        cout << is_mem_fun_ptr<B>::value << '\t';
        cout << is_mem_fun_ptr<C>::value << '\t';
        cout << is_mem_fun_ptr<D>::value << '\t';
        cout << is_mem_fun_ptr<int D::*>::value << '\t';
        cout << is_mem_fun_ptr<int (D::*)()>::value << '\t';
        cout << is_mem_fun_ptr<int (D::*)()const>::value << '\n';
    }
    

    sollte funktionieren (rvalue-Rereferenzen bei alten Compilern weglassen).


  • Mod

    Nochmal ein bisschen überarbeitet. Diese Version funktioniert mindestens ab gcc 3.4, Comeau-C++ und clang 3.1 sind auch zufrieden.
    rvalue-Referenzen und scoped enums werden unterstützt, es werden aber keine C++11-Features verwendet. Es sollte auch mit extended integer Typen funktionieren, allerdings kann ich das nicht testen.
    Was sagt Visual C++ dazu?

    #include <cstddef>
    
    template <bool b> struct bool_ { static const bool value = b; };
    template <typename T> struct not_ { static const bool value = !T::value; };
    typedef bool_<true> true_type;
    typedef bool_<false> false_type;
    
    template <typename T> struct identity { typedef T type; };
    
    template <typename T> struct is_void;
    template <typename T> struct is_array;
    template <typename T, bool = is_void<T>::value || is_array<T>::value> struct is_reference;
    template <typename T> struct is_class;
    
    // transformations
    template <typename T, bool = is_void<T>::value> struct add_reference : identity<T&> {};
    template <typename T, bool b> struct add_reference<T&, b> : identity<T&> {};
    template <typename T> struct add_reference<T, true> : identity<T> {};
    
    template <typename T, bool = is_void<T>::value> struct remove_reference : remove_reference<typename add_reference<T>::type> {};
    template <typename T, bool b> struct remove_reference<T&, b> : identity<T> {};
    template <typename T> struct remove_reference<T, true> : identity<T> {};
    
    template <typename T> struct remove_const : identity<T> {};
    template <typename T> struct remove_const<const T> : identity<T> {};
    
    template <typename T> struct remove_volatile : identity<T> {};
    template <typename T> struct remove_volatile<volatile T> : identity<T> {};
    
    template <typename T> struct remove_cv : remove_volatile<typename remove_const<T>::type> {};
    
    // relations
    template <typename T, typename U> struct is_same : false_type {};
    template <typename T> struct is_same<T, T> : true_type {};
    
    template <typename T, typename U, bool = is_void<T>::value> struct is_convertible
    {
        static typename add_reference<T>::type makeT();
        typedef char& yes_type;
        typedef char (&no_type)[2];
        template <typename V> static no_type test(...);
        template <typename V> static yes_type test(V);
        static const bool value = sizeof test<U>(makeT()) == sizeof(yes_type);
    };
    template <typename T, typename U> struct is_convertible<T[], U, false> : is_convertible<T*, U, false> {};
    template <typename T, std::size_t N, typename U> struct is_convertible<T[N], U, false> : is_convertible<T*, U, false> {};
    template <typename T, typename U> struct is_convertible<T, U, true> : is_void<U> {};
    
    // predicates
    template <typename T> struct is_void : is_same<typename remove_cv<T>::type, void> {};
    
    template <typename T> struct is_arithmetic : bool_<!is_class<T>::value && !is_reference<T>::value && is_convertible<T, int>::value && is_convertible<int, T>::value> {};
    
    template <typename T> struct is_fundamental: bool_<is_arithmetic<T>::value || is_void<T>::value> {};
    
    template <typename T> struct is_array : false_type {};
    template <typename T> struct is_array<T[]> : true_type {};
    template <typename T, std::size_t N> struct is_array<T[N]> : true_type {};
    
    template <typename T, bool = !is_void<T>::value && !is_reference<T>::value && !is_array<T>::value> struct is_function : is_same<void(T),void(T*)> {};
    template <typename T> struct is_function<T, false> : false_type {};
    
    template <typename T> struct is_object : bool_<!is_void<T>::value && !is_reference<T>::value && !is_function<T>::value> {};
    
    template <typename T> struct is_pointer : false_type {};
    template <typename T> struct is_pointer<T*> : true_type {};
    
    template <typename T, bool> struct is_reference : not_<is_same<T, typename remove_reference<typename add_reference<T>::type>::type> > {};
    template <typename T> struct is_reference<T, true> : false_type {};
    
    template <typename T> struct is_class
    {
        typedef char& yes_type;
        typedef char (&no_type)[2];
        template <typename U> static no_type test(...);
        template <typename U> static yes_type test(int U::*);
        static const bool value = sizeof test<T>(0) == sizeof(yes_type);
    };
    
    template <typename T> struct is_unscoped_enum : bool_<is_object<T>::value && !is_fundamental<T>::value && !is_class<T>::value && is_convertible<T, int>::value> {};
    
    template <typename T, bool = is_object<T>::value && !is_class<T>::value && !is_fundamental<T>::value && !is_array<T>::value
                                 && !is_pointer<T>::value && !is_unscoped_enum<T>::value>
    struct is_scoped_enum : not_<is_convertible<T, bool> > {};
    template <typename T> struct is_scoped_enum<T, false> : false_type {};
    
    template <typename T> struct is_enum : bool_<is_unscoped_enum<T>::value || is_scoped_enum<T>::value> {};
    
    template <typename T> struct is_mem_data_ptr : false_type {};
    template <typename T, typename C> struct is_mem_data_ptr<T C::*> : is_object<typename remove_reference<T>::type> {};
    
    template <typename T> struct is_mem_fun_ptr : bool_<is_object<T>::value && !is_class<T>::value && !is_fundamental<T>::value && !is_array<T>::value
    						    && !is_pointer<T>::value && !is_enum<T>::value && !is_mem_data_ptr<T>::value> {};
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <bool b> struct assertion_failure;
    template <> struct assertion_failure<true> : true_type {};
    
    #define FUSE( x, y ) x##y
    #define STATIC_ASSERT( T, x, v ) typedef int FUSE( assert, __LINE__ ) [sizeof(assertion_failure<T<x>::value==v>::value)]
    
    typedef int arithmetic_type;
    typedef void void_type;
    typedef int& lref_type;
    typedef int array_type[42];
    typedef int array_type2[];
    typedef int***** pointer_type;
    typedef int fun_type();
    typedef int(*pfun_type)();
    typedef int(&fun_ref_type)();
    enum enum_type {};
    struct struct_type {};
    union union_type {};
    typedef enum_type (struct_type::*mem_data_ptr_type_helper)() const;
    typedef mem_data_ptr_type_helper struct_type::*mem_data_ptr_type;
    typedef enum_type (struct_type::*mem_fun_ptr_type_)();
    typedef mem_data_ptr_type (struct_type::*mem_fun_ptr_type)() const;
    typedef mem_fun_ptr_type_ (struct_type::*mem_fun_ptr_type2)() const;
    
    #ifdef WITHCPP11
    enum class enum_class_type {};
    #define ENUM_CLASS_IS_SCOPED true
    typedef int&& rref_type;
    #else
    enum enum_class_type {};
    #define ENUM_CLASS_IS_SCOPED false
    typedef int& rref_type;
    #endif
    
    int main()
    {
        STATIC_ASSERT( is_class, arithmetic_type,   false );
        STATIC_ASSERT( is_class, void_type,         false );
        STATIC_ASSERT( is_class, lref_type,         false );
        STATIC_ASSERT( is_class, rref_type,         false );
        STATIC_ASSERT( is_class, array_type,        false );
        STATIC_ASSERT( is_class, array_type2,       false );
        STATIC_ASSERT( is_class, pointer_type,      false );
        STATIC_ASSERT( is_class, fun_type,          false );
        STATIC_ASSERT( is_class, pfun_type,         false );
        STATIC_ASSERT( is_class, fun_ref_type,      false );
        STATIC_ASSERT( is_class, enum_type,         false );
        STATIC_ASSERT( is_class, enum_class_type,   false );
        STATIC_ASSERT( is_class, struct_type,       true );
        STATIC_ASSERT( is_class, union_type,        true );
        STATIC_ASSERT( is_class, mem_data_ptr_type, false );
        STATIC_ASSERT( is_class, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_class, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_arithmetic, arithmetic_type,   true );
        STATIC_ASSERT( is_arithmetic, void_type,         false );
        STATIC_ASSERT( is_arithmetic, lref_type,         false );
        STATIC_ASSERT( is_arithmetic, rref_type,         false );
        STATIC_ASSERT( is_arithmetic, array_type,        false );
        STATIC_ASSERT( is_arithmetic, array_type2,       false );
        STATIC_ASSERT( is_arithmetic, pointer_type,      false );
        STATIC_ASSERT( is_arithmetic, fun_type,          false );
        STATIC_ASSERT( is_arithmetic, pfun_type,         false );
        STATIC_ASSERT( is_arithmetic, fun_ref_type,      false );
        STATIC_ASSERT( is_arithmetic, enum_type,         false );
        STATIC_ASSERT( is_arithmetic, enum_class_type,   false );
        STATIC_ASSERT( is_arithmetic, struct_type,       false);
        STATIC_ASSERT( is_arithmetic, union_type,        false);
        STATIC_ASSERT( is_arithmetic, mem_data_ptr_type, false );
        STATIC_ASSERT( is_arithmetic, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_arithmetic, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_void, arithmetic_type,   false );
        STATIC_ASSERT( is_void, void_type,         true );
        STATIC_ASSERT( is_void, lref_type,         false );
        STATIC_ASSERT( is_void, rref_type,         false );
        STATIC_ASSERT( is_void, array_type,        false );
        STATIC_ASSERT( is_void, array_type2,       false );
        STATIC_ASSERT( is_void, pointer_type,      false );
        STATIC_ASSERT( is_void, fun_type,          false );
        STATIC_ASSERT( is_void, pfun_type,         false );
        STATIC_ASSERT( is_void, fun_ref_type,      false );
        STATIC_ASSERT( is_void, enum_type,         false );
        STATIC_ASSERT( is_void, enum_class_type,   false );
        STATIC_ASSERT( is_void, struct_type,       false );
        STATIC_ASSERT( is_void, union_type,        false );
        STATIC_ASSERT( is_void, mem_data_ptr_type, false );
        STATIC_ASSERT( is_void, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_void, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_fundamental, arithmetic_type,   true );
        STATIC_ASSERT( is_fundamental, void_type,         true );
        STATIC_ASSERT( is_fundamental, lref_type,         false );
        STATIC_ASSERT( is_fundamental, rref_type,         false );
        STATIC_ASSERT( is_fundamental, array_type,        false );
        STATIC_ASSERT( is_fundamental, array_type2,       false );
        STATIC_ASSERT( is_fundamental, pointer_type,      false );
        STATIC_ASSERT( is_fundamental, fun_type,          false );
        STATIC_ASSERT( is_fundamental, pfun_type,         false );
        STATIC_ASSERT( is_fundamental, fun_ref_type,      false );
        STATIC_ASSERT( is_fundamental, enum_type,         false );
        STATIC_ASSERT( is_fundamental, enum_class_type,   false );
        STATIC_ASSERT( is_fundamental, struct_type,       false );
        STATIC_ASSERT( is_fundamental, union_type,        false );
        STATIC_ASSERT( is_fundamental, mem_data_ptr_type, false );
        STATIC_ASSERT( is_fundamental, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_fundamental, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_array, arithmetic_type,   false );
        STATIC_ASSERT( is_array, void_type,         false );
        STATIC_ASSERT( is_array, lref_type,         false );
        STATIC_ASSERT( is_array, rref_type,         false );
        STATIC_ASSERT( is_array, array_type,        true );
        STATIC_ASSERT( is_array, array_type2,       true );
        STATIC_ASSERT( is_array, pointer_type,      false );
        STATIC_ASSERT( is_array, fun_type,          false );
        STATIC_ASSERT( is_array, pfun_type,         false );
        STATIC_ASSERT( is_array, fun_ref_type,      false );
        STATIC_ASSERT( is_array, enum_type,         false );
        STATIC_ASSERT( is_array, enum_class_type,   false );
        STATIC_ASSERT( is_array, struct_type,       false );
        STATIC_ASSERT( is_array, union_type,        false );
        STATIC_ASSERT( is_array, mem_data_ptr_type, false );
        STATIC_ASSERT( is_array, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_array, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_reference, arithmetic_type,   false );
        STATIC_ASSERT( is_reference, void_type,         false );
        STATIC_ASSERT( is_reference, lref_type,         true );
        STATIC_ASSERT( is_reference, rref_type,         true );
        STATIC_ASSERT( is_reference, array_type,        false );
        STATIC_ASSERT( is_reference, array_type2,       false );
        STATIC_ASSERT( is_reference, pointer_type,      false );
        STATIC_ASSERT( is_reference, fun_type,          false );
        STATIC_ASSERT( is_reference, pfun_type,         false );
        STATIC_ASSERT( is_reference, fun_ref_type,      true );
        STATIC_ASSERT( is_reference, enum_type,         false );
        STATIC_ASSERT( is_reference, enum_class_type,   false );
        STATIC_ASSERT( is_reference, struct_type,       false );
        STATIC_ASSERT( is_reference, union_type,        false );
        STATIC_ASSERT( is_reference, mem_data_ptr_type, false );
        STATIC_ASSERT( is_reference, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_reference, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_pointer, arithmetic_type,   false );
        STATIC_ASSERT( is_pointer, void_type,         false );
        STATIC_ASSERT( is_pointer, lref_type,         false );
        STATIC_ASSERT( is_pointer, rref_type,         false );
        STATIC_ASSERT( is_pointer, array_type,        false );
        STATIC_ASSERT( is_pointer, array_type2,       false );
        STATIC_ASSERT( is_pointer, pointer_type,      true );
        STATIC_ASSERT( is_pointer, fun_type,          false );
        STATIC_ASSERT( is_pointer, pfun_type,         true );
        STATIC_ASSERT( is_pointer, fun_ref_type,      false );
        STATIC_ASSERT( is_pointer, enum_type,         false );
        STATIC_ASSERT( is_pointer, enum_class_type,   false );
        STATIC_ASSERT( is_pointer, struct_type,       false );
        STATIC_ASSERT( is_pointer, union_type,        false );
        STATIC_ASSERT( is_pointer, mem_data_ptr_type, false );
        STATIC_ASSERT( is_pointer, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_pointer, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_object, arithmetic_type,   true );
        STATIC_ASSERT( is_object, void_type,         false );
        STATIC_ASSERT( is_object, lref_type,         false );
        STATIC_ASSERT( is_object, rref_type,         false );
        STATIC_ASSERT( is_object, array_type,        true );
        STATIC_ASSERT( is_object, array_type2,       true );
        STATIC_ASSERT( is_object, pointer_type,      true );
        STATIC_ASSERT( is_object, fun_type,          false );
        STATIC_ASSERT( is_object, pfun_type,         true );
        STATIC_ASSERT( is_object, fun_ref_type,      false );
        STATIC_ASSERT( is_object, enum_type,         true );
        STATIC_ASSERT( is_object, enum_class_type,   true );
        STATIC_ASSERT( is_object, struct_type,       true );
        STATIC_ASSERT( is_object, union_type,        true );
        STATIC_ASSERT( is_object, mem_data_ptr_type, true );
        STATIC_ASSERT( is_object, mem_fun_ptr_type,  true );
        STATIC_ASSERT( is_object, mem_fun_ptr_type2, true );
    
        STATIC_ASSERT( is_function, arithmetic_type,   false );
        STATIC_ASSERT( is_function, void_type,         false );
        STATIC_ASSERT( is_function, lref_type,         false );
        STATIC_ASSERT( is_function, rref_type,         false );
        STATIC_ASSERT( is_function, array_type,        false );
        STATIC_ASSERT( is_function, array_type2,       false );
        STATIC_ASSERT( is_function, pointer_type,      false );
        STATIC_ASSERT( is_function, fun_type,          true );
        STATIC_ASSERT( is_function, pfun_type,         false );
        STATIC_ASSERT( is_function, fun_ref_type,      false );
        STATIC_ASSERT( is_function, enum_type,         false );
        STATIC_ASSERT( is_function, enum_class_type,   false );
        STATIC_ASSERT( is_function, struct_type,       false );
        STATIC_ASSERT( is_function, union_type,        false );
        STATIC_ASSERT( is_function, mem_data_ptr_type, false );
        STATIC_ASSERT( is_function, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_function, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_unscoped_enum, arithmetic_type,   false );
        STATIC_ASSERT( is_unscoped_enum, void_type,         false );
        STATIC_ASSERT( is_unscoped_enum, lref_type,         false );
        STATIC_ASSERT( is_unscoped_enum, rref_type,         false );
        STATIC_ASSERT( is_unscoped_enum, array_type,        false );
        STATIC_ASSERT( is_unscoped_enum, array_type2,       false );
        STATIC_ASSERT( is_unscoped_enum, pointer_type,      false );
        STATIC_ASSERT( is_unscoped_enum, fun_type,          false );
        STATIC_ASSERT( is_unscoped_enum, pfun_type,         false );
        STATIC_ASSERT( is_unscoped_enum, fun_ref_type,      false );
        STATIC_ASSERT( is_unscoped_enum, enum_type,         true );
        STATIC_ASSERT( is_unscoped_enum, enum_class_type,   !ENUM_CLASS_IS_SCOPED );
        STATIC_ASSERT( is_unscoped_enum, struct_type,       false );
        STATIC_ASSERT( is_unscoped_enum, union_type,        false );
        STATIC_ASSERT( is_unscoped_enum, mem_data_ptr_type, false );
        STATIC_ASSERT( is_unscoped_enum, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_unscoped_enum, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_scoped_enum, arithmetic_type,   false );
        STATIC_ASSERT( is_scoped_enum, void_type,         false );
        STATIC_ASSERT( is_scoped_enum, lref_type,         false );
        STATIC_ASSERT( is_scoped_enum, rref_type,         false );
        STATIC_ASSERT( is_scoped_enum, array_type,        false );
        STATIC_ASSERT( is_scoped_enum, array_type2,       false );
        STATIC_ASSERT( is_scoped_enum, pointer_type,      false );
        STATIC_ASSERT( is_scoped_enum, fun_type,          false );
        STATIC_ASSERT( is_scoped_enum, pfun_type,         false );
        STATIC_ASSERT( is_scoped_enum, fun_ref_type,      false );
        STATIC_ASSERT( is_scoped_enum, enum_type,         false );
        STATIC_ASSERT( is_scoped_enum, enum_class_type,   ENUM_CLASS_IS_SCOPED );
        STATIC_ASSERT( is_scoped_enum, struct_type,       false );
        STATIC_ASSERT( is_scoped_enum, union_type,        false );
        STATIC_ASSERT( is_scoped_enum, mem_data_ptr_type, false );
        STATIC_ASSERT( is_scoped_enum, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_scoped_enum, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_enum, arithmetic_type,   false );
        STATIC_ASSERT( is_enum, void_type,         false );
        STATIC_ASSERT( is_enum, lref_type,         false );
        STATIC_ASSERT( is_enum, rref_type,         false );
        STATIC_ASSERT( is_enum, array_type,        false );
        STATIC_ASSERT( is_enum, array_type2,       false );
        STATIC_ASSERT( is_enum, pointer_type,      false );
        STATIC_ASSERT( is_enum, fun_type,          false );
        STATIC_ASSERT( is_enum, pfun_type,         false );
        STATIC_ASSERT( is_enum, fun_ref_type,      false );
        STATIC_ASSERT( is_enum, enum_type,         true );
        STATIC_ASSERT( is_enum, enum_class_type,   true );
        STATIC_ASSERT( is_enum, struct_type,       false );
        STATIC_ASSERT( is_enum, union_type,        false );
        STATIC_ASSERT( is_enum, mem_data_ptr_type, false );
        STATIC_ASSERT( is_enum, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_enum, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_mem_data_ptr, arithmetic_type,   false );
        STATIC_ASSERT( is_mem_data_ptr, void_type,         false );
        STATIC_ASSERT( is_mem_data_ptr, lref_type,         false );
        STATIC_ASSERT( is_mem_data_ptr, rref_type,         false );
        STATIC_ASSERT( is_mem_data_ptr, array_type,        false );
        STATIC_ASSERT( is_mem_data_ptr, array_type2,       false );
        STATIC_ASSERT( is_mem_data_ptr, pointer_type,      false );
        STATIC_ASSERT( is_mem_data_ptr, fun_type,          false );
        STATIC_ASSERT( is_mem_data_ptr, pfun_type,         false );
        STATIC_ASSERT( is_mem_data_ptr, fun_ref_type,      false );
        STATIC_ASSERT( is_mem_data_ptr, enum_type,         false );
        STATIC_ASSERT( is_mem_data_ptr, enum_class_type,   false );
        STATIC_ASSERT( is_mem_data_ptr, struct_type,       false );
        STATIC_ASSERT( is_mem_data_ptr, union_type,        false );
        STATIC_ASSERT( is_mem_data_ptr, mem_data_ptr_type, true );
        STATIC_ASSERT( is_mem_data_ptr, mem_fun_ptr_type,  false );
        STATIC_ASSERT( is_mem_data_ptr, mem_fun_ptr_type2, false );
    
        STATIC_ASSERT( is_mem_fun_ptr, arithmetic_type,   false );
        STATIC_ASSERT( is_mem_fun_ptr, void_type,         false );
        STATIC_ASSERT( is_mem_fun_ptr, lref_type,         false );
        STATIC_ASSERT( is_mem_fun_ptr, rref_type,         false );
        STATIC_ASSERT( is_mem_fun_ptr, array_type,        false );
        STATIC_ASSERT( is_mem_fun_ptr, array_type2,       false );
        STATIC_ASSERT( is_mem_fun_ptr, pointer_type,      false );
        STATIC_ASSERT( is_mem_fun_ptr, fun_type,          false );
        STATIC_ASSERT( is_mem_fun_ptr, pfun_type,         false );
        STATIC_ASSERT( is_mem_fun_ptr, fun_ref_type,      false );
        STATIC_ASSERT( is_mem_fun_ptr, enum_type,         false );
        STATIC_ASSERT( is_mem_fun_ptr, enum_class_type,   false );
        STATIC_ASSERT( is_mem_fun_ptr, struct_type,       false );
        STATIC_ASSERT( is_mem_fun_ptr, union_type,        false );
        STATIC_ASSERT( is_mem_fun_ptr, mem_data_ptr_type, false );
        STATIC_ASSERT( is_mem_fun_ptr, mem_fun_ptr_type,  true );
        STATIC_ASSERT( is_mem_fun_ptr, mem_fun_ptr_type2, true );
    }
    


  • VS 10 mag den Code nicht so sehr:

    Microsoft (R) 32-Bit C/C++-Optimierungscompiler Version 16.00.40219.01 für 80x86
    Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.
    
    memfn.cpp
    memfn.cpp(15) : error C2265: 'T': Verweis auf ein Array der Größe Null ist ungültig
            memfn.cpp(63): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "add_reference<T>".
            with
            [
                T=array_type2 
            ]
            memfn.cpp(49): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "is_reference<T>".
            with
            [
                T=array_type2 
            ]
            memfn.cpp(142): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "is_arithmetic<T>".
            with
            [
                T=array_type2
            ]
    memfn.cpp(214) : error C2027: Verwendung des undefinierten Typs "assertion_failure<b>"
            with
            [
                b=false
            ]
    memfn.cpp(214) : error C2065: 'value': nichtdeklarierter Bezeichner
    memfn.cpp(214) : error C2070: ''unknown-type'': Ungültiger sizeof-Operand
    memfn.cpp(214) : error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.
    memfn.cpp(214) : error C2086: 'int assert__LINE__[1]': Neudefinition
            memfn.cpp(119): Siehe Deklaration von 'assert__LINE__'
    memfn.cpp(332) : error C2027: Verwendung des undefinierten Typs "assertion_failure<b>"
            with
            [
                b=false
            ]
    memfn.cpp(332) : error C2065: 'value': nichtdeklarierter Bezeichner
    memfn.cpp(332) : error C2070: ''unknown-type'': Ungültiger sizeof-Operand
    memfn.cpp(332) : error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.
    memfn.cpp(332) : error C2086: 'int assert__LINE__[1]': Neudefinition
            memfn.cpp(119): Siehe Deklaration von 'assert__LINE__'
    memfn.cpp(350) : error C2027: Verwendung des undefinierten Typs "assertion_failure<b>"
            with
            [
                b=false
            ]
    memfn.cpp(350) : error C2065: 'value': nichtdeklarierter Bezeichner
    memfn.cpp(350) : error C2070: ''unknown-type'': Ungültiger sizeof-Operand
    memfn.cpp(350) : error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.
    memfn.cpp(350) : error C2086: 'int assert__LINE__[1]': Neudefinition
            memfn.cpp(119): Siehe Deklaration von 'assert__LINE__'
    

  • Mod

    Etwas geändert, um den ersten Fehler zu beseitigen.
    Edit: noch ein paar probleme mit g++ 4.0-4.3 beseitigt (getestet mit 3.4.6, 4.0.4, 4.1.2, 4.2.4, 4.3.6, 4.4.6, 4.5.3, 4.6.3, 4.7.1, 4.8.0 alpha). g++ 3.3.6 kommt offenbar nicht mit dem SFINAE-Trick zurecht.
    Die Logik bei Zeigern auf Member wurde geändert. Jetzt funktioniert es vermutlich auch mit vc2010.



  • Okay, kompiliert jetzt auch unter VS 2008:
    aber mit warnungen:

    STATIC_ASSERT( is_scoped_enum, arithmetic_type,   false );
    

    ..\..\..\..\Project\src\Main\Main.cpp(225) : warning C4800: 'arithmetic_type' : forcing value to bool 'true' or 'false' (performance warning)
    1> ..\..\..\..\Project\src\Main\Main.cpp(267) : see reference to class template instantiation 'is_convertible<T,U>' being compiled
    1> with
    1> [
    1> T=arithmetic_type,
    1> U=bool
    1> ]
    1> ..\..\..\..\Project\src\Main\Main.cpp(470) : see reference to class template instantiation 'is_scoped_enum<T>' being compiled
    1> with
    1> [
    1> T=arithmetic_type
    1> ]
    1>..\..\..\..\Project\src\Main\Main.cpp(225) : warning C4800: 'arithmetic_type' : forcing value to bool 'true' or 'false' (performance warning)
    1> ..\..\..\..\Project\src\Main\Main.cpp(267) : see reference to class template instantiation 'is_convertible<T,U>' being compiled
    1> with
    1> [
    1> T=lref_type ,
    1> U=bool
    1> ]
    1> ..\..\..\..\Project\src\Main\Main.cpp(472) : see reference to class template instantiation 'is_scoped_enum<T>' being compiled
    1> with
    1> [
    1> T=lref_type
    1> ]


Anmelden zum Antworten