[SOLVED] Template-Spezialisierung für alle abgeleiteten Klassen
-
Hallo zusammen,
irgendwie kommt mir das Problem bekannt vor, finde aber keinen passenden Post.
Ich möchte, dass meine Template-Spezialisierung auch für alle davon abgeleiteten Klassen greift. Natürlich ist das eigentliche Problem komplexer, aber prinzipiell meine ich folgendes:
struct Foo{}; struct Bar : public Foo{}; template<typename T> struct FooBar; template<> struct FooBar<Foo> { typedef int type; }; int main(){ FooBar<Foo>::type v1; FooBar<Bar>::type v2; }test.cpp: In function 'int main()':
test.cpp:15:2: error: incomplete type 'FooBar<Bar>' used in nested name specifier
test.cpp:15:20: error: expected ';' before 'v2'Also ich möchte auf einen
typedefzugreifen, was aber nur funktioniert
wenn ich als Parameter an meine Template-Funktion genau ein Foo übergeben
kriege, bei Bar greift die Template-Spezialisierung (verständlicherweise) nicht.
Wie lautet der zu empfehlende Ansatz/Workaround?Gruß,
XSpille
-
Ich weiß nicht, ob ich mich erinnert habe oder selbst den Einfall hatte:
#include <boost/type_traits/is_base_of.hpp> struct Foo{}; struct Bar : public Foo{}; template<typename T, bool B = boost::is_base_of<Foo, T>::value> struct FooBar; template<typename T> struct FooBar<T, true> { typedef int type; }; int main(){ FooBar<Foo>::type v1; FooBar<Bar>::type v2; }Falls es doch noch eine elegantere Lösung gibt, bin ich dankbar

Gruß,
XSpille
-
Irgendwie komm ich nicht weiter...
also eigentlich wollte ich den angeführten Code für Template-Klassen mit variadic Parametern
verwenden.#include <boost/type_traits/is_base_of.hpp> template<typename... T> struct Foo{}; template<typename... T> struct Bar : public Foo<T...>{}; template<typename T, bool B = boost::is_base_of<Foo<...>, T>::value> // Klar funct das '...' so nicht, aber es verdeutlicht wohl, was ich möchte struct FooBar; template<typename T> struct FooBar<T, true> { typedef int type; }; int main(){ FooBar<Foo<int> >::type v1; FooBar<Bar<double> >::type v2; }Ich hoffe ihr versteht, was ich möchte.
Habt ihr evtl. irgendwelche Lösungsideen/-vorschläge?Gruß,
XSpille
-
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 arrayDu 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 arrayDu 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.
-
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