Check für is member function pointer


  • 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> ]


  • Mod

    Bitte noch mal mit der aktuellen Version probieren.



  • Ich hatte meine letzte message editiert, die Warnungen hast du gesehen?

    aber hey, sieht nicht schlecht aus, ist das ein kompletter type_traits ersatz für C++03?

    Was mir so btw. auffällt ist, das du glaube keine compound typen behandelst,
    also z.B.

    int**** foo;
    

    In dem Buch löst er das dadurch, das er das template immer wieder mit sich selbst aufruft.



  • Nash26 schrieb:

    Was mir so btw. auffällt ist, das du glaube keine compound typen behandelst,
    also z.B.

    int**** foo;
    

    Ohne näher Bezug zum Code zu nehmen, sei hier angemerkt, dass das auch "nur" ein Zeiger ist.


  • Mod

    Nash26 schrieb:

    Ich hatte meine letzte message editiert, die Warnungen hast du gesehen?

    aber hey, sieht nicht schlecht aus, ist das ein kompletter type_traits ersatz für C++03?

    Was mir so btw. auffällt ist, das du glaube keine compound typen behandelst,
    also z.B.

    int**** foo;
    

    In dem Buch löst er das dadurch, das er das template immer wieder mit sich selbst aufruft.

    Die Warnung ist harmlos, ich habe aber den Code nochmal geändert, das sollte jetzt ohne diese Warnung compilieren.

    Ich habe auch noch mal die Erkennung von Zeigern auf Member geändert, der Workaround zuvor war falsch. Hoffentlich funktioniert das weiterhin mit Visual C++ 2010.
    G++ 4.0-4.3 zerlegt Zeiger auf konstante Memberfunktionen in eine Referenz und den Klassenbezug (und hoffentlich ist das auch das Problem bei Visual C++ 2010, dann funktiniert der Workaround). Indem ich jetzt dort (Zeile 92) die Referenz entferne (die dort eigentlich nie auftreten kann, denn Zeiger auf Member verweisen niemals auf Referenzen), funktioniert es jetzt wieder mit allen g++-Versionen ab 3.4.

    Ich habe auch den Test auf int***** eingebaut (deshalb die vielen typedefs, um leicht mit verschiedenen Typen spielen zu können). Eine rekursive Behandlung ist in der Regel nicht erforderlich.



  • STATIC_ASSERT( is_function, fun_type,          true );
    

    ..\..\..\..\Project\src\Main\Main.cpp(449) : error C2027: use of undefined type 'assertion_failure<b>'
    1> with
    1> [
    1> b=false
    1> ]
    1>..\..\..\..\Project\src\Main\Main.cpp(449) : error C2065: 'value' : undeclared identifier
    1>..\..\..\..\Project\src\Main\Main.cpp(449) : error C2070: ''unknown-type'': illegal sizeof operand
    1>..\..\..\..\Project\src\Main\Main.cpp(449) : error C2466: cannot allocate an array of constant size 0
    1>..\..\..\..\Project\src\Main\Main.cpp(449) : error C2086: 'int assert__LINE__[1]' : redefinition
    1> ..\..\..\..\Project\src\Main\Main.cpp(316) : see declaration of 'assert__LINE__'
    1>..\..\..\..\Project\src\Main\Main.cpp(224) : warning C4800: 'fun_type (__cdecl *)' : forcing value to bool 'true' or 'false' (performance warning)
    1> ..\..\..\..\Project\src\Main\Main.cpp(185) : see reference to class template instantiation 'is_convertible<T,U>' being compiled
    1> with
    1> [
    1> T=fun_type ,
    1> U=bool
    1> ]
    1> ..\..\..\..\Project\src\Main\Main.cpp(267) : see reference to class template instantiation 'not_<T>' being compiled
    1> with
    1> [
    1> T=is_convertible<fun_type ,bool>
    1> ]
    1> ..\..\..\..\Project\src\Main\Main.cpp(485) : see reference to class template instantiation 'is_scoped_enum<T>' being compiled
    1> with
    1> [
    1> T=fun_type
    1> ]
    1>..\..\..\..\Project\src\Main\Main.cpp(539) : error C2027: use of undefined type 'assertion_failure<b>'
    1> with
    1> [
    1> b=false
    1> ]


  • Mod

    Fehler in is_object behoben. Bitte noch mal testen, mit und ohne Compilererweiterungen.



  • 1>  main.cpp
    1>main.cpp(266): error C2027: use of undefined type 'assertion_failure<b>'
    1>          with
    1>          [
    1>              b=false
    1>          ]
    1>main.cpp(266): error C2065: 'value' : undeclared identifier
    1>main.cpp(266): error C2070: ''unknown-type'': illegal sizeof operand
    1>main.cpp(266): error C2466: cannot allocate an array of constant size 0
    1>main.cpp(266): error C2086: 'int assert__LINE__[1]' : redefinition
    1>          main.cpp(133) : see declaration of 'assert__LINE__'
    1>main.cpp(284): error C2027: use of undefined type 'assertion_failure<b>'
    1>          with
    1>          [
    1>              b=false
    1>          ]
    1>main.cpp(284): error C2065: 'value' : undeclared identifier
    1>main.cpp(284): error C2070: ''unknown-type'': illegal sizeof operand
    1>main.cpp(284): error C2466: cannot allocate an array of constant size 0
    1>main.cpp(284): error C2086: 'int assert__LINE__[1]' : redefinition
    1>          main.cpp(133) : see declaration of 'assert__LINE__'
    1>main.cpp(43): warning C4800: 'fun_type (__cdecl *)' : forcing value to bool 'true' or 'false' (performance warning)
    1>          main.cpp(4) : see reference to class template instantiation 'is_convertible<T,U>' being compiled
    1>          with
    1>          [
    1>              T=fun_type ,
    1>              U=bool
    1>          ]
    1>          main.cpp(85) : see reference to class template instantiation 'not_<T>' being compiled
    1>          with
    1>          [
    1>              T=is_convertible<fun_type ,bool>
    1>          ]
    1>          main.cpp(320) : see reference to class template instantiation 'is_scoped_enum<T>' being compiled
    1>          with
    1>          [
    1>              T=fun_type
    1>          ]
    1>main.cpp(374): error C2027: use of undefined type 'assertion_failure<b>'
    1>          with
    1>          [
    1>              b=false
    1>          ]
    1>main.cpp(374): error C2065: 'value' : undeclared identifier
    1>main.cpp(374): error C2070: ''unknown-type'': illegal sizeof operand
    1>main.cpp(374): error C2466: cannot allocate an array of constant size 0
    1>main.cpp(374): error C2086: 'int assert__LINE__[1]' : redefinition
    1>          main.cpp(133) : see declaration of 'assert__LINE__'
    1>
    1>Build FAILED.
    

    Ohne Compilererweiterungen geht's.


  • Mod

    Swordfish schrieb:

    Ohne Compilererweiterungen geht's.

    Funktionszeiger können bei Visual C++ implizit in void* konvertiert werden? Wie unsinnig...
    Ich habe es nochmal geändert, der ursprüngliche is_function-Code schien ja zu funktionieren.



  • camper schrieb:

    Funktionszeiger können bei Visual C++ implizit in void* konvertiert werden?

    Ja.

    camper schrieb:

    Ich habe es nochmal geändert, [...]

    Besser. 😉



  • also wenn ich mir deinen code so anschaue, ist es deutlich weniger als bei boost.
    bleibt die frage warum die es nicht auch so implementieren?

    PS: bei mir kompilliert es nun ohne Fehler und Warnung durch.


  • Mod

    Nash26 schrieb:

    also wenn ich mir deinen code so anschaue, ist es deutlich weniger als bei boost.
    bleibt die frage warum die es nicht auch so implementieren?

    Weil es offensichtlich mit vielen alten Compilern so nicht funktioniert.
    Ich habe das Ganze nochmal etwas überarbeitet. Jetzt wird auch nullptr_t richtig erkannt.
    Außerdem ist jetzt klarer, dass nur die is_xxx-Prädikate angeboten werden; die anderen Hilfstemplates sind nur für die Implementation da (die reagieren recht allergisch auf ungünstige Parameter besonders mit kaputten Compilern).

    Eine vollständige Traits-Bbliothek kann das nicht ersetzen, ich betrachte es nur als kleine Übung. Viele der interessanteren Traits sind ohnehin nicht ohne spezielle Compilerunterstützung/-kenntnis implementierbar.

    #include <cstddef>
    
    namespace ttraits
    {
        namespace detail
        {
            template <bool b> struct bool_ { static const bool value = b; };
    
            typedef bool_<true>  true_type;
            typedef bool_<false> false_type;
    
            template <typename T> struct not_ : bool_<!T::value> {};
    
            template <typename T> struct identity { typedef T type; };
    
            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> struct is_same_ : is_same<typename T::type, typename U::type> {};
    
            template <typename T> struct add_reference                      : identity<T&>                  {};
            template <typename T> struct add_reference<T&>                  : identity<T&>                  {};
    
            template <typename T> struct remove_reference                      : remove_reference<typename add_reference<T>::type> {};
            template <typename T> struct remove_reference<T&>                  : identity<T>                                       {};
    
            template <bool b, typename T, typename U> struct if_c              : T {};
            template <typename T, typename U>         struct if_c<false, T, U> : U {};
    
            template <typename C, typename T, typename U> struct if_ : if_c<C::value, T, U> {};
    
            typedef char& yes_type;
            typedef char (&no_type)[2];
    
            template <typename T, typename U> struct is_convertible
            {
                static no_type test(...);
                static yes_type test(U);
                static T makeT;
                static const bool value = sizeof test(makeT) == sizeof(yes_type);
            };
    
            template <typename T> struct is_function_helper : is_same<void(T), void(T*)> {};
    
            template <typename T> struct is_class_helper
            {
                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_void                      : detail::false_type {};
        template <>           struct is_void<void>                : detail::true_type  {};
        template <>           struct is_void<const void>          : detail::true_type  {};
        template <>           struct is_void<volatile void>       : detail::true_type  {};
        template <>           struct is_void<const volatile void> : detail::true_type  {};
    
        template <typename T>                struct is_array       : detail::false_type {};
        template <typename T>                struct is_array<T[]>  : detail::true_type  {};
        template <typename T, std::size_t N> struct is_array<T[N]> : detail::true_type  {};
    
        template <typename T> struct is_pointer     : detail::false_type {};
        template <typename T> struct is_pointer<T*> : detail::true_type {};
    
        template <typename T > struct is_reference : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value,
            detail::false_type,
            detail::not_<detail::is_same_<detail::identity<T>, detail::remove_reference<T> > > > {};
    
        template <typename T> struct is_class : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value || is_reference<T>::value,
            detail::false_type,
            detail::is_class_helper<T> > {};
    
        template <typename T> struct is_function : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value || is_reference<T>::value || is_class<T>::value,
            detail::false_type,
            detail::is_function_helper<T> > {};
    
        template <typename T> struct is_nullptr_t : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value || is_reference<T>::value || is_class<T>::value || is_function<T>::value,
            detail::false_type,
            detail::if_<
                detail::is_convertible<T, char*>,
                detail::is_convertible<T, int*>,
                detail::false_type> > {};
    
        template <typename T> struct is_arithmetic : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value || is_reference<T>::value || is_class<T>::value || is_function<T>::value
                || is_nullptr_t<T>::value,
            detail::false_type,
            detail::if_<
                detail::is_convertible<T, int>,
                detail::is_convertible<int, T>,
                detail::false_type> > {};
    
        template <typename T> struct is_unscoped_enum : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value || is_reference<T>::value || is_class<T>::value || is_function<T>::value
                || is_nullptr_t<T>::value || is_arithmetic<T>::value,
            detail::false_type,
            detail::is_convertible<T, int> > {};
    
        template <typename T> struct is_scoped_enum : detail::if_c<
            is_void<T>::value || is_array<T>::value || is_pointer<T>::value || is_reference<T>::value || is_class<T>::value || is_function<T>::value
                || is_nullptr_t<T>::value || is_arithmetic<T>::value || is_unscoped_enum<T>::value,
            detail::false_type,
            detail::not_<detail::is_convertible<T, bool> > > {};
    
        template <typename T> struct is_object : detail::bool_<!is_void<T>::value && !is_reference<T>::value && !is_function<T>::value> {};
    
        template <typename T> struct is_mem_data_ptr : detail::false_type {};
        template <typename T, typename C> struct is_mem_data_ptr<T C::*> : is_object<T> {};
    
        template <typename T> struct is_fundamental : detail::bool_<is_void<T>::value || is_nullptr_t<T>::value || is_arithmetic<T>::value> {};
    
        template <typename T> struct is_enum : detail::bool_<is_unscoped_enum<T>::value || is_scoped_enum<T>::value> {};
    
        template <typename T> struct is_udt : detail::bool_<is_class<T>::value || is_enum<T>::value> {};
    
        template <typename T> struct is_mem_fun_ptr : detail::bool_<is_object<T>::value && !is_udt<T>::value && !is_fundamental<T>::value
            && !is_array<T>::value && !is_pointer<T>::value && !is_mem_data_ptr<T>::value> {};
    
        template <typename T> struct is_mem_ptr : detail::bool_<is_mem_data_ptr<T>::value || is_mem_fun_ptr<T>::value> {};
    
        template <typename T> struct is_scalar : detail::bool_<is_nullptr_t<T>::value || is_arithmetic<T>::value || is_pointer<T>::value || is_mem_ptr<T>::value || is_enum<T>::value> {};
    
        template <typename T> struct is_compound : detail::bool_<!is_fundamental<T>::value> {};
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    using namespace ttraits;
    template <bool b> struct assertion_failure;
    template <> struct assertion_failure<true> : detail::true_type {};
    
    #define TEST( T, x ) typedef int foo[sizeof(assertion_failure<T<x>::value>::value)]
    #define TEST_ALL( T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, x ) \
        TEST(T0,x); TEST(T1,x); TEST(T2,x); TEST(T3,x); TEST(T4,x); TEST(T5,x); TEST(T6,x); TEST(T7,x); TEST(T8,x); TEST(T9,x); TEST(T10,x); TEST(T11,x); TEST(T12,x); TEST(T13,x); TEST(T14,x); TEST(T15,x); TEST(T16,x); TEST(T17,x)
    
    TEST_ALL(!is_void, is_arithmetic,!is_nullptr_t, is_fundamental,!is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object, is_scalar, int );
    TEST_ALL( is_void,!is_arithmetic,!is_nullptr_t, is_fundamental,!is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt,!is_object,!is_scalar, void );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer, is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt,!is_object,!is_scalar, int& );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer, is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt,!is_object,!is_scalar, int(&)() );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound, is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object,!is_scalar, int[42] );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound, is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object,!is_scalar, int[] );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array, is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object, is_scalar, int* );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array, is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object, is_scalar, int(*)() );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference, is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt,!is_object,!is_scalar, int() );
    enum A {};
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class, is_unscoped_enum,!is_scoped_enum, is_enum,!is_mem_data_ptr,!is_mem_fun_ptr, is_udt, is_object, is_scalar, A );
    struct B {};
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function, is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr, is_udt, is_object,!is_scalar, B );
    union C {};
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function, is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr, is_udt, is_object,!is_scalar, C );
    struct D;
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function, is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr, is_udt, is_object,!is_scalar, D );
    struct E { virtual ~E() = 0; };
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function, is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr, is_udt, is_object,!is_scalar, E );
    
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum, is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object, is_scalar, D D::* );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr, is_mem_fun_ptr,!is_udt, is_object, is_scalar, D (D::*)() );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr, is_mem_fun_ptr,!is_udt, is_object, is_scalar, D (D::*)() const );
    
    #ifdef WITHCPP11
    enum class Z;
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum, is_scoped_enum, is_enum,!is_mem_data_ptr,!is_mem_fun_ptr, is_udt, is_object, is_scalar, Z );
    TEST_ALL(!is_void,!is_arithmetic,!is_nullptr_t,!is_fundamental, is_compound,!is_array,!is_pointer, is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt,!is_object,!is_scalar, int&& );
    TEST_ALL(!is_void,!is_arithmetic, is_nullptr_t, is_fundamental,!is_compound,!is_array,!is_pointer,!is_reference,!is_function,!is_class,!is_unscoped_enum,!is_scoped_enum,!is_enum,!is_mem_data_ptr,!is_mem_fun_ptr,!is_udt, is_object, is_scalar, std::nullptr_t );
    #endif
    
    int main() {}
    

Anmelden zum Antworten