Templatespezialisierung: Unterscheidung pointer und non-pointer type



  • Hi,
    ich versuche gerade eine Klasse Foo zusammen zu basteln, die folgendes möglich macht:

    Foo<int, -1> a;
    Foo<void*, nullptr> b;
    

    Die Klasse braucht einen Typ und einen ungültigen Wert für diesen Typ.

    Mein Versuch:

    template<typename Type, Type invalid>
    struct Foo
    {
    	Type value = invalid;
    };
    
    template<typename Type, Type* invalid>
    struct Foo<Type*, invalid>
    {
    	Type value = invalid;
    	int i;
    };
    
    int main()
    {
    	Foo<int, -1> a;
    	a.value = 5;
    	Foo<void*, nullptr> b;
    	b.i = 5;
    }
    

    ➡ main.cpp:19:4: error: no member named 'i' in 'Foo<void *, nullptr>'

    Anscheinend wird die Spezialisierunug nicht gematcht. Wie würde es richtig aussehen?


  • Mod

    template<typename Type, Type *invalid>
    struct Foo<Type*, invalid>
    {
        Type *value = invalid;
        int i;
    };
    


  • Zeile 10:

    Type* value = invalid;
    

    Anschließend compiliert und läuft es (Visual Studio 12)



  • Selber Fehler. Aber du hast recht, in der Spezialisierung müsste es Type* sein.

    Nachtrag: clang++ 3.8.1 gibt mir den Fehler, g++ 6.2.1 akzeptiert den Code. clang Bug?



  • Biolunar schrieb:

    Selber Fehler. Aber du hast recht, in der Spezialisierung müsste es Type* sein.

    Nachtrag: clang++ 3.8.1 gibt mir den Fehler, g++ 6.2.1 akzeptiert den Code. clang Bug?

    Nach meinem Verständnis wüsste ich nicht weshalb er auch im void* -Fall nicht das erste Template instanzieren dürfte:

    template<Type = void*, void* invalid = nullptr>
    struct Foo
    {
        void* value = nullptr;
    };
    

    Sowas ähnliches hatte ich auch schon öfter und habe da bisher immer mit std::enable_if<std::is_pointer<Type>> gearbeitet.

    Gruss,
    Finnegan

    P.S.: Wenn man wissen möchte wie man Pointer grundsätzlich unterscheidet, lohnt es sich vielleicht mal eine Implementierung von std::is_pointer anzusehen. So auf Anhieb wüsse ich nicht wie ich da rangehen würde.



  • Finnegan schrieb:

    Nach meinem Verständnis wüsste ich nicht weshalb er auch im void* -Fall nicht das erste Template instanzieren dürfte […]

    Siehe 1) auf http://en.cppreference.com/w/cpp/language/partial_specialization#Partial_ordering

    Habe mein Problem nun anders gelöst (ohne Spezialisierung). Trotzdem merkwürdig, dass clang den Code nicht mag.


  • Mod

    Das Problem hat etwas mit Templateargumentdeduktion zu tun. Wenn wir das Ganze etwas umschreiben:

    template <typename T, T x> struct S {};
    template <typename T, T x>
    char foo(S<T, x>);
    
    static_assert( sizeof(foo(S<void*,nullptr>{}))==1, "");
    

    hat clang weiterhin die gleichen Schwierigkeiten.


Anmelden zum Antworten