variadic template parameters: parameter-type zur laufzeit auswaehlen
-
hallo leute,
gibt es eine moeglichkeit das ich via template - metaprogrammierung mir zur laufzeit den type eines template-parameters ueber den index holen kann? wobei der index bei 1 beginnt.
kurzes beispiel:
template<class PARAM1, class... PARAMS> struct test_throw { auto throw_per_index(unsigned int idx) -> void { if(idx!= 0) { throw do_magic_and_throw(idx); } } };
nun wuerde ich das gerne so anwenden koennen (nur ein beispiel):
test_throw<std::bad_alloc, std::out_of_range> test2; ... extern unsigned int val; ... if(val != 0) test2.throw_per_index(val);
geht sowas?
Meep Meep
-
Was meinst du mit "holen"?
-
hi camper,
hierbei geht es um die member function do_magic_and_throw.
sie soll automatisch ueber den index den richtigen template-parameter type rausfinden und als exception werfen.kurz mal mit pseudecode:
//als template parameter wird std::bad_alloc und std::out_of_range uebergeben auto test_throw::do_magic_and_throw(unsigned int idx) -> void { if(idx == 1) throw std::bad_alloc(); else if(idx == 2) throw std::out_of_range(); }
mit holen meinte ich den richtigen type aus der template-parameterliste raussuchen/holen.
Meep Meep
-
Hi meep meep, da du leider nicht zeigst, was du mit dem parametertypen anstellen möchtest kann ich auch nur raten, ob du so etwas meinst:
#include <string> #include <typeinfo> using namespace std; template<unsigned int N, typename Param1, typename... Params> struct ParamType { using value_type = typename ParamType<N -1, Params...>::value_type; static const char* name() { return typeid( value_type ).name(); } }; template<typename Param1, typename... Params> struct ParamType<1,Param1,Params...> { using value_type = Param1; static const char* name() { return typeid( value_type ).name(); } }; template<typename Param1, typename... Params> struct ParamType<0,Param1,Params...>; int main() { const char* n1 = typeid( ParamType<1,int,double,bool,std::string>::value_type ).name(); const char* n2 = typeid( ParamType<2,int,double,bool,std::string>::value_type ).name(); const char* n3 = typeid( ParamType<3,int,double,bool,std::string>::value_type ).name(); const char* n4 = typeid( ParamType<4,int,double,bool,std::string>::value_type ).name(); const char* m1 = ParamType<1,int,double,bool,std::string>::name(); const char* m2 = ParamType<2,int,double,bool,std::string>::name(); const char* m3 = ParamType<3,int,double,bool,std::string>::name(); const char* m4 = ParamType<4,int,double,bool,std::string>::name(); }
-
Mittels std::tuple - s. get the Nth type of variadic template templates?
-
Sachen gibt´s...
Danke für die Verbesserung
-
ok.
z.B. klassisch rekursiv:auto test_throw::do_magic_and_throw(unsigned int idx) -> void { if(idx == 1) throw PARAM1(); else if constexpr (sizeof...(PARAMS) != 0) // bzw. entsprechend spezialisieren test_throw<PARAMS...>::do_magic_and_throw(idx-1); };
oder per LUT
auto test_throw::do_magic_and_throw(unsigned int idx) -> void { static void ((*const)throws())[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... }; if(idx-1 < std::size(throws)) throws[idx-1](); };
oder per fold-Ausdruck (lohnt vom Aufwand her eher nur, wenn bereits eine Indexliste existiert).
-
danke euch fuer die hilfe.
Meep Meep
-
static void ((*const)throws())[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
using fun = void(*)(); static const fun throws[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
-
Arcoth schrieb:
static void ((*const)throws())[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
using fun = void(*)(); static const fun throws[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
Einzeiler rulz
void do_magic_and_throw(unsigned int idx) { (void(*[])()){ [] {}, [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... }[idx<=sizeof...(PARAMS)+1?idx:0](); }
-
camper schrieb:
Einzeiler rulz
(void(*[])()){ [] {}, [] {
Mal ganz ernsthaft: ist sowas noch lesbar?
Ich schreibe ja auch gern in Perl und es wurde der Sprache immer vorgeworfen, sie sei nicht lesbar wegen der Sonderzeichen. Aber das hier ist doch nicht besser: 17 Sonderzeichen hinter dem void! Ernsthaft? Gut, []{} ist z.B. schnell als leeres Lambda identifiziert, und nach längerem Hingucken verstehe ich sogar den ganzen Ausdruck. Geht das nicht in verständlicher?
-
wob schrieb:
camper schrieb:
Einzeiler rulz
(void(*[])()){ [] {}, [] {
Mal ganz ernsthaft: ist sowas noch lesbar?
Der ernsthafte Teil des Threads ist zu Ende, jetzt ist Feierabend. Ein Lisp-Programmierer dürfte sich wohlfühlen, und immerhin ist es nicht immer dieselbe Klammerart.
-
camper schrieb:
Arcoth schrieb:
static void ((*const)throws())[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
using fun = void(*)(); static const fun throws[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
Einzeiler rulz
void do_magic_and_throw(unsigned int idx) { (void(*[])()){ [] {}, [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... }[idx<=sizeof...(PARAMS)+1?idx:0](); }
Ist das überhaupt gültiges C++? IIRC ist
T[]
keine gültige type-id in einer functional cast expression.
-
Arcoth schrieb:
IIRC ist
T[]
keine gültige type-id in einer functional cast expression.In C++03 hättest du noch recht gehabt.Edit: Err. du hast recht, aber hier haben wir (T)x also Explicit type conversion (cast notation).
-
camper schrieb:
Arcoth schrieb:
IIRC ist
T[]
keine gültige type-id in einer functional cast expression.In C++03 hättest du noch recht gehabt.
Ich bin mir ziemlich sicher, dass ich immer noch Recht habe.
-
korrigiert.
-
camper schrieb:
Edit: Err. du hast recht, aber hier haben wir (T)x also Explicit type conversion (cast notation).
Genau genommen haben wir hier überhaupt nichts, weil das einfach kein gültiges Produkt der Grammatik ist.
Edit: Also ich hätte nichts gegen compound literals in C++. Proposal?
-
Arcoth schrieb:
camper schrieb:
Edit: Err. du hast recht, aber hier haben wir (T)x also Explicit type conversion (cast notation).
Genau genommen haben wir hier überhaupt nichts, weil das einfach kein gültiges Produkt der Grammatik ist.
Komisch, dass kein vernünftiger moderner Compiler damit Probleme hat. (Visual C++ zählt nicht). Diese Behauptung müsstest du also noch begründen.
-
camper schrieb:
Arcoth schrieb:
camper schrieb:
Edit: Err. du hast recht, aber hier haben wir (T)x also Explicit type conversion (cast notation).
Genau genommen haben wir hier überhaupt nichts, weil das einfach kein gültiges Produkt der Grammatik ist.
Komisch, dass kein vernünftiger moderner Compiler damit Probleme hat. (Visual C++ zählt nicht). Diese Behauptung müsstest du also noch begründen.
Ist das dein Ernst? Schalte mal deine Warnungen an. GCC und Clang beschweren sich mit "ISO C++ forbids compound-literals", und die Grammatik von cast-expressions verlangt eindeutig nach einem Ausdruck nach dem eingeklammerten Typen. Du stimmst sicher zu, dass
{...}
kein Ausdruck ist.(Visual C++ zählt nicht).
Visual C++ ist zumindest im Frontend auf EDG basiert, welches relativ akkurat sein dürfte (glaub ich). Kenne mich damit aber zu wenig aus.
-
Ok. Schön. Aus irgendeinem Grunde war -pedantic bei mir nicht pedantisch genug
Es scheint also, dass so oder so irgend ein Name für etwas (Typ oder Variable nach Belieben) eingeführt werden muss. Wie super überflüssig