[c++0x] sfinae und variadic template constructor
-
Hi, ist es möglich in diesem fall möglich sfinaes zu verwenden?
struct Test{ template<class...Args> Test( Args...Data) {/*....*/} };
in vorraus dankend
VCPL
-
Was willst du hier mit SFINAE herausfinden?
-
wxSkip schrieb:
Was willst du hier mit SFINAE herausfinden?
Ich möchte bestimmte Parameter konstalationen ausschliesen, da sonst fehler entstehen. Auserdem gibt std::is_convertible immer true, obwohl es nicht immer stimmt.
Ich möchte z.B verbieten das der erste typ sein int sein darf.In der regel kann man ja ein dummy zeiger als letzten parameter nehmen und darauf sfinae anwenden; aber in diesem fall muss das parameter pack am ende sein...
eigentlich könnte man alles in eine init funktion auslagern welche alles macht und über dem konstruktor diese aufrufen, dann habe ich aber probleme wie :
- std::is_convertible gibt immer true
- ich keine anderen Konstruktoren haben darf
-
struct Test; template<typename... Args> struct do_if_not_int { static void init(Test *obj, Args... args); }; template<typename... Args> struct do_if_not_int<int, Args...>; struct Test{ template<class...Args> Test( Args...Data) { do_if_not_int::init(this, Data...); //wenn der erste Parameter int ist kommt gleich error: use of incomplete struct do_if_not_int } }; template<typename... Args> void do_if_not_int<Args...>::init(Test *obj, Args... args) { //... }
-
wxSkip schrieb:
struct Test; template<typename... Args> struct do_if_not_int { static void init(Test *obj, Args... args); }; template<typename... Args> struct do_if_not_int<int, Args...>; struct Test{ template<class...Args> Test( Args...Data) { do_if_not_int::init(this, Data...); //wenn der erste Parameter int ist kommt gleich error: use of incomplete struct do_if_not_int } }; template<typename... Args> void do_if_not_int<Args...>::init(Test *obj, Args... args) { //... }
Danke für die mühe, das ist allerdings nicht das was ich suche...ich glaub ich habe mich etwas falsch ausgedrückt...
In deinem beispiel wird nicht der Konstruktor ausgeschlossen, der Compiler kann meckert nur weil der Konstruktor unter bestimmten Umständen "do_if_not_int::init" nicht verwenden kann, ich möchte aber das der Konstruktor als möglicher Kandidat bei der Substitution bei der Compilierung ausgeschlossen wird.Ein beispiel bei dem es wichtig sein könnte:
struct Test{ Test(); Test(int); template<class...Args> Test( Args...Data); };
Mir ist klar das man das auch so schreiben könnte:
struct Test{ template<class...Args> Test( Args...Data) { Set(Data...); } template<class Arg, class...Args> typename std::enable_if<!std::is_same<Arg>::value,void>::type Set( Arg Data0, Args...Data); template<class Arg, class...Args> typename std::enable_if</*Andere Variante*/,void>::type Set( Arg Data0, Args...Data); };
Das Problem ist allerdings das ansiech die Klasse Test, einen Konstruktor besitzt für jede erdenkliche Parameter Kombi hat- glaubt der Compiler zumindest.
Man kann, wie du sicher weist, über SFINAE viele informationen über eine Klasse erhalten und entsprechend dessen, vieles tun.
Wenn man mit SFINAE informationen von der klasse Test ermittelt zb. WELCHE Konstruktoren es hat, dann zieht man falsche rückschlüsse daraus. std::is_convertible ist ein beispiel davon...Ich denke es ist nun Klar wieso man den ctor komplett als Kandidaten ausschliesen muss; meine frage ist, ob es in dem Fall überhaupt möglich ist dies zu tun.
Als alternative bietet sich natürlich eine freie/statische funktion zu definieren die, die Konstruktion übernimmt aber das ist etwas unpraktisch.
-
Und wenn du den Konstruktor mit int, Args... überlädtst und ihn private machst?
-
Heho, ich hab gerade das gleiche Problem. Es kann doch nicht sein, dass der Workaround mit std::enable_if (nur) bei variadischen Konstruktoren nicht funktioniert. Weiss jemand mehr dazu?
Ich beziehe mich auf das da:
VCPL schrieb:
struct Test{ Test(); Test(int); template<class...Args> Test( Args...Data); };
Das Problem ist allerdings das ansiech die Klasse Test, einen Konstruktor besitzt für jede erdenkliche Parameter Kombi hat- glaubt der Compiler zumindest.
Zum Beispiel sollen alle Args nur
std::is_pointer
sein.
-
ansiech schrieb:
Zum Beispiel sollen alle Args nur
std::is_pointer
sein.Blödes Beispiel. Sagen wir halt
std::is_integral
.
-
Ich fürchte, das wird so nicht gehen. Grund: Du kannst zwar mit Templates herausfinden, ob alle Werte dem Prädikat genügen, aber du kannst diese Prüfung nirgends einbauen. Du kannst sie nicht in der Templateliste nach Args... angeben, weil variadic Templates immer am Schluss stehen müssen. Du kannst sie nicht in der Rückgabe anbringen, weil es keine gibt. Und du kannst sie nicht in der Argumentliste anbringen, weil der Compiler dann die Typen nicht mehr deduzieren könnte.
-
#include <utility> #include <type_traits> template <template <typename> class pred, typename...> struct query_all; template <template <typename> class pred> struct query_all<pred> : std::integral_constant<bool, true> {}; template <template <typename> class pred, typename T, typename... Args> struct query_all<pred, T, Args...> : std::integral_constant<bool, pred<T>::value && query_all<pred, Args...>::value> {}; struct Test { template<typename... T, typename = typename std::enable_if<query_all<std::is_integral, T...>::value>::type> Test(T...) {} };
-
wxSkip schrieb:
Ich fürchte, das wird so nicht gehen. Grund: Du kannst zwar mit Templates herausfinden, ob alle Werte dem Prädikat genügen, aber du kannst diese Prüfung nirgends einbauen. Du kannst sie nicht in der Templateliste nach Args... angeben, weil variadic Templates immer am Schluss stehen müssen. Du kannst sie nicht in der Rückgabe anbringen, weil es keine gibt. Und du kannst sie nicht in der Argumentliste anbringen, weil der Compiler dann die Typen nicht mehr deduzieren könnte.
Etwas genauer muss es schon sein:
Für primäre Klassentemplates gilt, dass ein evtl. vorhandenes Parameterpack an letzter Stelle stehen muss.
Bei Funktionstemplates muss ein Parameterpack an letzter Stelle der Funktionsparameterliste stehen. Es gibt keine besonderen Beschränkungen für die Templateparameter eines Funktionstemplates oder für Templatespezialisierungen (sind auch nicht notwendig).
-
camper schrieb:
wxSkip schrieb:
Ich fürchte, das wird so nicht gehen. Grund: Du kannst zwar mit Templates herausfinden, ob alle Werte dem Prädikat genügen, aber du kannst diese Prüfung nirgends einbauen. Du kannst sie nicht in der Templateliste nach Args... angeben, weil variadic Templates immer am Schluss stehen müssen. Du kannst sie nicht in der Rückgabe anbringen, weil es keine gibt. Und du kannst sie nicht in der Argumentliste anbringen, weil der Compiler dann die Typen nicht mehr deduzieren könnte.
Etwas genauer muss es schon sein:
Für primäre Klassentemplates gilt, dass ein evtl. vorhandenes Parameterpack an letzter Stelle stehen muss.
Bei Funktionstemplates muss ein Parameterpack an letzter Stelle der Funktionsparameterliste stehen. Es gibt keine besonderen Beschränkungen für die Templateparameter eines Funktionstemplates oder für Templatespezialisierungen (sind auch nicht notwendig).Okay, das wusste ich nicht.
-
camper schrieb:
#include <utility> #include <type_traits> template <template <typename> class pred, typename...> struct query_all; template <template <typename> class pred> struct query_all<pred> : std::integral_constant<bool, true> {}; template <template <typename> class pred, typename T, typename... Args> struct query_all<pred, T, Args...> : std::integral_constant<bool, pred<T>::value && query_all<pred, Args...>::value> {}; struct Test { template<typename... T, typename = typename std::enable_if<query_all<std::is_integral, T...>::value>::type> Test(T...) {} };
Jetzt hab ich nicht nur eine fertige Lösung, sondern auch ein grösseres Verständnis. Vielen Dank, camper!