[SOLVED] Template-Spezialisierung für alle abgeleiteten Klassen



  • spontan muss ich da an SFINAE denken...



  • Vielleicht mit eigenem is_derived_of_foo (ungetestet):

    typedef char FalseType;
    typedef struct{char s[2];} TrueType;
    
    template<typename... Templates> TrueType is_derived_of_foo_function(Foo<Templates...> *ptr);
    FalseType is_derived_of_foo_function(...);
    
    template<typename T> class is_derived_of_foo
    {
        static const bool value = (sizeof(is_derived_of_foo_function((T*)0)) == sizeof(TrueType);
    }
    

    Ich habe aber eine leise Vorahnung, dass das nicht gehen könnte.



  • Wie wärs wenn du dein variadic class template von einer ganz normalen class ableitest?

    class all_foo_base
    {
    };
    
    template< class ... >
    class Foo
        : all_foo_base
    {
    };
    

    und dann einfach mit

    is_base_of< all_foo_base, T >
    

    überprüfen, ob T ein Foo<...> ist



  • Ich danke euch beiden 🙂

    @wxSkip: Abgesehen von 2 Kleinigkeiten, mußt nur eine Referenz zurückliefern (EDIT: FALSCH!!! siehe unten),
    aber ansonsten perfekt 👍

    Hier noch 'meine' funktionierende Lösung:

    #include <iostream>
    
    template<typename... T>
    struct Foo{};
    
    template<typename... T>
    struct Bar : public Foo<T...>{};
    
    typedef char FalseType[1]; 
    typedef char TrueType[2]; 
    
    template<typename... Templates> TrueType& is_derived_of_foo_function(Foo<Templates...> *ptr); 
    FalseType& is_derived_of_foo_function(...); 
    
    template<typename T> struct is_derived_of_foo{ 
    	static const bool value = (sizeof(is_derived_of_foo_function((T*)0)) == sizeof(TrueType)); 
    };
    
    template<typename T, bool B = is_derived_of_foo<T>::value >
    struct FooBar;
    
    template<typename T>
    struct FooBar<T, true> {
    	typedef int type;
    };
    
    int main(){
    	std::cout << is_derived_of_foo<int>::value << std::endl;
    	std::cout << is_derived_of_foo<Foo<int> >::value << std::endl;
    	std::cout << is_derived_of_foo<Bar<int> >::value << std::endl;
    	FooBar<Foo<int> >::type v1;
    	FooBar<Bar<double> >::type v2;
    }
    

    @GorbGorb: Danke, aber ich wollte die Verwebungshierarchie nicht anpassen



  • @XSpille: Wozu die Referenz?



  • wxSkip schrieb:

    @XSpille: Wozu die Referenz?

    Ehrlich gesagt: Keine Ahnung...

    sonst kriegt man folgende Fehlermeldung, die ich ehrlich gesagt nicht ganz verstehe...

    test.cpp:12:91: error: 'is_derived_of_foo_function' declared as function returning an array
    test.cpp:13:41: error: 'is_derived_of_foo_function' declared as function returning an array



  • XSpille schrieb:

    wxSkip schrieb:

    @XSpille: Wozu die Referenz?

    Ehrlich gesagt: Keine Ahnung...

    sonst kriegt man folgende Fehlermeldung, die ich ehrlich gesagt nicht ganz verstehe...

    test.cpp:12:91: error: 'is_derived_of_foo_function' declared as function returning an array
    test.cpp:13:41: error: 'is_derived_of_foo_function' declared as function returning an array

    Du darfst kein Array zurückgeben, deswegen habe ich auch ein struct darum gemacht... 🙄



  • wxSkip schrieb:

    XSpille schrieb:

    wxSkip schrieb:

    @XSpille: Wozu die Referenz?

    Ehrlich gesagt: Keine Ahnung...

    sonst kriegt man folgende Fehlermeldung, die ich ehrlich gesagt nicht ganz verstehe...

    test.cpp:12:91: error: 'is_derived_of_foo_function' declared as function returning an array
    test.cpp:13:41: error: 'is_derived_of_foo_function' declared as function returning an array

    Du darfst kein Array zurückgeben, deswegen habe ich auch ein struct darum gemacht... 🙄

    Ok... Du hast recht! Dann hab ich den Fehler reingemacht 🙂



  • Eine Frsge hab ich doch noch 🙂

    Hat die Variante mit Hilfe von sizeof in C++0x einen Vorteil gegenüber der folgenden decltype-Version, die ich persönlich schöner finde:

    typedef struct{} no; 
    typedef struct{} yes;
    
    template<typename... T>
    struct Foo{};
    
    template<typename... T>
    struct Bar : public Foo<T...>{};
    
    template<typename... Templates> yes is_derived_of_foo_function(Foo<Templates...> *ptr); 
    no is_derived_of_foo_function(...); 
    
    template<typename T> struct is_derived_of_foo 
    { 
        typedef decltype(is_derived_of_foo_function(static_cast<T*>(0))) type; 
    };
    
    template<typename T, typename B = typename is_derived_of_foo<T>::type >
    struct FooBar;
    
    template<typename T>
    struct FooBar<T, yes> {
    	typedef int type;
    };
    
    int main(){
    	FooBar<Foo<int> >::type v1;
    	FooBar<Bar<double> >::type v2;
    	//FooBar<int>::type v3;
    }
    


  • XSpille schrieb:

    Eine Frsge hab ich doch noch 🙂

    Hat die Variante mit Hilfe von sizeof in C++0x einen Vorteil gegenüber der folgenden decltype-Version, die ich persönlich schöner finde:

    typedef struct{} no; 
    typedef struct{} yes;
    
    template<typename... T>
    struct Foo{};
    
    template<typename... T>
    struct Bar : public Foo<T...>{};
    
    template<typename... Templates> yes is_derived_of_foo_function(Foo<Templates...> *ptr); 
    no is_derived_of_foo_function(...); 
    
    template<typename T> struct is_derived_of_foo 
    { 
        typedef decltype(is_derived_of_foo_function(static_cast<T*>(0))) type; 
    };
    
    template<typename T, typename B = typename is_derived_of_foo<T>::type >
    struct FooBar;
    
    template<typename T>
    struct FooBar<T, yes> {
    	typedef int type;
    };
    
    int main(){
    	FooBar<Foo<int> >::type v1;
    	FooBar<Bar<double> >::type v2;
    	//FooBar<int>::type v3;
    }
    

    Sofern du es nicht als Boolean weiterverwenden willst, wüsste ich keinen Nachteil. Allerdings bin ich etwas überrascht, dass das funktioniert, schließlich haben no und yes doch eigentlich den gleichen Typ und sollten auch nicht vom Namen her bevorzugt werden, da dieser ja noch einmal getypedef't wird.



  • wxSkip schrieb:

    schließlich haben no und yes doch eigentlich den gleichen Typ

    Nö, das sind doch völlig unabhängige Definitionen.
    Aber warum typedef struct{} no; statt struct no{};?



  • volkard schrieb:

    wxSkip schrieb:

    schließlich haben no und yes doch eigentlich den gleichen Typ

    Nö, das sind doch völlig unabhängige Definitionen.
    Aber warum typedef struct{} no; statt struct no{};?

    Ach so, das gilt dann nur bei 2 Typedefs auf char, dass die untereinander konvertibel sind? Eigentlich ja logisch.


  • Mod

    wxSkip schrieb:

    volkard schrieb:

    wxSkip schrieb:

    schließlich haben no und yes doch eigentlich den gleichen Typ

    Nö, das sind doch völlig unabhängige Definitionen.
    Aber warum typedef struct{} no; statt struct no{};?

    Ach so, das gilt dann nur bei 2 Typedefs auf char, dass die untereinander konvertibel sind? Eigentlich ja logisch.

    Hier greift eine Sonderbehandlung von unbenannten Klassen in typedefs, der typedef-Name wird fürs Linken verwendet, somit sind mehrere solche Deklarationen mit unterschiedlichen Namen auch verschieden.

    7.1.3 The typedef specifier [dcl.typedef]
    ...
    9 If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the declaration to be that class type (or enum type) is used to denote the class type (or enum type) for linkage purposes only (3.5).
    [ Example:

    typedef struct { } *ps, S; // S is the class name for linkage purposes

    —end example ]

    Edit:

    9.1 Class names [class.name]
    1 A class definition introduces a new type.

    ist noch einfacher. Da hier mehrere Klassendefinitionen vorliegen, definiert jede einen anderen Typ, unamhängig davon, ob es nun struct foo{} oder typedef struct {} foo heißt.



  • Danke euch allen! 👍

    volkard schrieb:

    Aber warum typedef struct{} no; statt struct no{};?

    Hast du völlig recht...
    Weil es aus der anderen Version entstanden ist 🤡


Anmelden zum Antworten