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


  • Mod

    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();
    }
    




  • Sachen gibt´s...
    Danke für die Verbesserung 👍


  • Mod

    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


  • Mod

    static void ((*const)throws())[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
    

    ➡

    using fun = void(*)();
       static const fun throws[] = { [] { throw PARAM1{}; }, [] { throw PARAMS{}; }... };
    

  • Mod

    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?


  • Mod

    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.


  • Mod

    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.


  • Mod

    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).


  • Mod

    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.


  • Mod

    korrigiert.


  • Mod

    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? 🙂


  • Mod

    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.


  • Mod

    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.


  • Mod

    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 😞


Anmelden zum Antworten