Parameter-Pack lässt sich nicht entpacken?



  • Hallo!
    Vor graumer Zeit habe ich einen Thread eröffnet, in dem mir KK einen netten Lösungsvorschlag mit TMP zeigte. Das Problem:
    Ich will zur Compiletime einen Index in eine Index-Liste (per Parameter-Pack) verwandeln, etwa so:

    typename make_list<6u>::type list;
    // List soll jetzt das int-Pack beinhalten, sprich soll der Typ
    // make_list<6u>::type<0, 1, 2, 3, 4, 5> sein
    function(list)...;
    /* Das soll dann zu
    function(0), function(1) ... function(5);
    werden
    */
    

    Um das zu testen habe ich folgenden Code geschrieben:

    #include <iostream>
    #include <cstdlib>
    
    template <typename T>
    struct id {
    	typedef T type;
    };
    
    template <unsigned...>
    struct pack { };
    
    template <unsigned head, unsigned... tail>
    struct pack_index {
    	typedef typename pack_index<head - 1, head - 1, tail...>::type type;
    };
    
    template <unsigned... tail>
    struct pack_index<0u, tail...> {
    	typedef pack<tail...> type;
    };
    
    void fun(unsigned e) {
    	std::cout << e << ' ';
    }
    
    int main() {
    	typename id<typename pack_index<6u>::type>::type packet; //ja, sieht komisch aus
    	std::cout << typeid(packet).name() << std::endl;
    	fun(packet)...;
    	std::system("pause");
    }
    

    Am Ende will ich also schön die Ausgabe 0 1 2 3 4 5 erhalten, klappt aber nicht mit:

    error: cannot convert 'id<pack<0u, 1u, 2u, 3u, 4u, 5u> >::type' to 'unsigned int' for argument '1' to 'void fun(unsigned int)'
    error: expected ';' before '...' token
    

    Was mache ich falsch?

    Compiler: G++ 4.5.0
    kompiliert mit c++ -Wall -o result.exe -std=c++0x main.cpp



  • Da steht cannot convert er denkt warscheinlich das das strings oder so sind weil er es nicht in unsigned int umwandeln kann. Und lass hinter fun(packet) die ... weg vielleicht hilfts.



  • Nö, der Elipsen-Operator (...) ist dort schon richtig gewählt (hoffe ich), da ich ja den Pack in seine einzelnen unsigned-Bestandteile aufteilen will. Er will hier aber scheinbar nicht entpacken, sondern den Pack so übergeben.



  • Hi,

    [quote="Ad aCTa"]

    typename make_list<6u>::type list;
    // List soll jetzt das int-Pack beinhalten, sprich soll der Typ
    // make_list<6u>::type<0, 1, 2, 3, 4, 5> sein
    function(list)...;
    /* Das soll dann zu
    function(0), function(1) ... function(5);
    werden
    */
    

    Das wird leider nicht funktionieren, da make_list<6>::type ein TYP und kein Parameter_PACK ist. Egal wie du es auch drehst, in C++ kannst du nur ein Typ instantiieren.
    Was du aber tun könntest ist ist eine Klasse zu schreiben die einen Funktor und den TYP "Pack" als template-parameter entgegen nimmt und anschließend evaluiert, zu Proggen.

    Pack und make_Pack könnte so aussehen:

    template<unsigned...Args>
    class Pack
    {
      template<uint I, unsigned Arg0, unsigned...Args>
      class Iterator : public Iterator<I-1,Args...>
      {};
    
      template<unsigned Arg0, unsigned...Args>
      struct Iterator<0,Arg0,Args...>
      {
        enum eResult{ Result = Arg0 };
      };
    
      template<uint I>
      class Pack_Iterator<I>
      {};
    
    public:
    
      enum eSize : unsigned { Size = sizeof...(Args) };
    
      typedef Pack<Args...> type;
    
      template<uint...E>
      struct Prepend : public Pack<E...,Args...>
      {};
    
      template<uint I>
      struct Get : public Iterator<I,Args...>
      {
        enum eIndex{ Index = I };
      };
    
    };
    
    template<uint I,class Result=Pack<> >
    class Make_Pack : public Make_Pack<I-1,typename Result::template Prepend<I>::type>
    {};
    
    template<class Result>
    class Make_Pack<0> : public Result::template Prepend<0>::type
    {};
    
    //--------------------------------------------------------------
    
    template<class aPack, class Functor> // Boost::Functor oder Signal&Slot würde ich dir zu herzen legen
    class Eval
    {
    Functor functor;
    
    ....
    public:
    
    template<uint I = aPack::Size-1>
    inline Ruckgabetyp DoIt()
    {
      if(I) this->functor( aPack::template Get<I>::Result );
      ....
    }
    
    };
    

    Das dürfte dir den nötigen Denkanstoß liefern...

    MFG Speed

    ps. Bastle grad an einer Variadic Template Library ca in einem monat dürfte sie Release-bereit sein ;P



  • Ad aCTa schrieb:

    Was mache ich falsch?

    • "typename" in main ist da (außerhalb von Templates) falsch.
    • "id<blah>::type" ist überflüssig und kann durch "blah" ersetzt werden.
    • Du versuchst den Pack-Expansions-Operator auf etwas anzuwenden, was kein "Pack" enthält. Es heißt nur so. "Packs" gibt es nur innerhalb von Templates. Das sind entweder "Template-Parameter-Packs" oder "Funktions-Parameter-Packs".
    • In diesem Kontext ist der Pack-Expansions-Operator sowieso nicht anwendbar. Das klappt typischerweise nur innerhalb von Klammern, also (p...) --> (p1,p2,p3) und <p...> --> <p1,p2,p3> aber auch bei Vererbung hinter dem Doppelpunkt. Im aktuellen Entwurf gibt es irgendwo eine Liste, die genau sagt, wann und wo der Operator auftreten darf. Die habe ich gerade nicht im Kopf.
    #include <iostream>
    
    using namespace std;
    
    // ic = integral constant wrapped in a type
    template<class T, T Const>
    struct ic { static const T value = Const; };
    
    template<class...> // Unbenanntes Template-(Typ-)Parameter-Pack
    struct typelist {};
    
    void foo(unsigned i) {
      cout << i << '\n';
    }
    
    void bar(typelist<>) {}
    
    template<class T, class...More> // More ist ein Template-(Typ-)Parameter-Pack
    void bar(typelist<T,More...>)
    {
      foo(T::value); // T = ic<unsigned,wert> mit T::value=wert
      bar(typelist<More...>()); // <-- Legales "Auspacken"
    }
    
    template<unsigned...UInts> // UInts ist ein Template-(int-)Parameter-Pack
    typelist<ic<unsigned,UInts>...> uints2typelist();
    //                         ^^^
    //               Auspacken hier erlaubt
    
    int main() {
      // Hier gibt's keine auspackbaren "Packs"
      typedef decltype( uints2typelist<1,2,3,5,8,13>() ) fibonacci;
      bar(fibonacci());
    }
    

    kk



  • > Das wird leider nicht funktionieren, da make_list<6>::type ein TYP und kein Parameter_PACK ist.

    KK hat allerdings im früheren Thread gesagt, dass die Template Argument Deduction das auflösen könne:

    krümelkacker schrieb:

    [...]
    Es löst das Problem, an ein geeignetes Int-Parameter-Pack zu kommen. Der passende Typ kann über Metaprogrammierung erzeugt werden. Das Int-Parameter-Pack bekommt man dann über die Template-Argument-Deduktion. Das heißt, wenn ich einen Typen wie ipack<0,1,2,3,4,5> über Metaprogrammierung erzeugen kann, kann ich die Funktion

    template<class Tuple, int... Ints>
    void weiter(Tuple t, ipack<Ints...>)
    {
       foo(std::get<Ints>(t)...);
    }
    

    so aufrufen:

    const int N = tuple_size<my_tuple_type>::value;
    typedef mach_mir_ein_ipack<0,N>::type indices; // = ipack<0,1,2,3,4,5>
    weiter( my_tuple, indices() );
    

    Über die Regeln der Template-Argument-Deduktion kommt der Compiler selbst auf die Templateparameter, nämlich

    Tuple   = std::tuple<irgendwelche Typen>
    Ints... = 0,1,2,3,4,5
    


  • Ad aCTa schrieb:

    > Das wird leider nicht funktionieren, da make_list<6>::type ein TYP und kein Parameter_PACK ist.

    KK hat allerdings im früheren Thread gesagt, dass die Template Argument Deduction das auflösen könne:

    Dass heist trozdem nicht, make_list<6>::type sei ein Parameter Pack( und mit dem Pack-Expansions-Operator auspackbar) ... wie auch immer über "Template Argument Deduction" kann man aus dem Objekt - über dessen Typ, das Parameter Pack wieder extrahieren(und anschliesend entpacken).

    In meinem vorherigen Post kannst du lesen wie man das Paket Packt , in Krümmelkackers Fehler im Code und wie man das Packet richtig auspackt ;P



  • Speed schrieb:

    In meinem vorherigen Post kannst du lesen wie man das Paket Packt , in Krümmelkackers Fehler im Code und wie man das Packet richtig auspackt ;P

    Wie bitte? Ich verstehe den Teil des Satzes nicht.



  • @Krümmelkacker : Au ja, der Satz ist Müll. Ich sollte ab Mitternacht keine Post mehr schreiben.
    Meinte nur, das du in deinen Post, ihn auf seine Fehler aufmerksam gemacht hast.

    MFG Speed


Anmelden zum Antworten