Wie lauten die Regeln für das Token “…” im Kontext variadischer Vorlagen?

In C ++ 11 gibt es variadische Vorlagen wie diese:

template unique_ptr make_unique( Args&&... args ) { return unique_ptr(new T(std::forward(args)...)); } 

Es gibt einige Besonderheiten: Der Ausdruck std::forward(args)... verwendet sowohl Args als auch Args aber nur ein ... token. Außerdem ist std::forward eine nicht-variadische Template-function, die nur einen Template-Parameter und ein Argument verwendet. Was sind die Syntaxregeln dafür (grob)? Wie kann es verallgemeinert werden?

Außerdem: In der functionsimplementierung steht die Ellipse ( ... ) am Ende des interessierenden Ausdrucks. Gibt es einen Grund, dass in der Vorlagenargumentliste und der Parameterliste die Ellipsen in der Mitte sind?

   

    Im Kontext von variadic template wird die Ellipse ... verwendet, um das Vorlagenparameterpaket zu entpacken, wenn es auf der rechten Seite eines Ausdrucks erscheint (rufen Sie dieses Ausdrucksmuster für einen Moment auf). Die Regel ist, dass jedes Muster auf der linken Seite von ... wiederholt wird – die entpackten Muster (nennen sie jetzt Ausdrücke ) werden durch Komma getrennt.

    Es kann am besten durch einige Beispiele verstanden werden. Angenommen, Sie haben diese functionsvorlage:

     template void f(T ... args) { g( args... ); //pattern = args h( x(args)... ); //pattern = x(args) m( y(args...) ); //pattern = args (as argument to y()) n( z(args)... ); //pattern = z(args) } 

    Wenn ich nun diese function {int, char, short} indem ich T als {int, char, short} , dann wird jeder functionsaufruf folgendermaßen erweitert:

     g( arg0, arg1, arg2 ); h( x(arg0), x(arg1), x(arg2) ); m( y(arg0, arg1, arg2) ); n( z(arg0), z(arg1), z(arg2) ); 

    In dem von Ihnen geposteten Code folgt std::forward dem vierten Muster, das durch den functionsaufruf n() wird.

    Beachten Sie den Unterschied zwischen x(args)... und y(args...) oben!


    Sie können ... ein Array auch folgendermaßen initialisieren:

     struct data_info { boost::any data; std::size_t type_size; }; std::vector v{{args, sizeof(T)}...}; //pattern = {args, sizeof(T)} 

    was zu diesem erweitert wird:

     std::vector v { {arg0, sizeof(int)}, {arg1, sizeof(char)}, {arg2, sizeof(short)} }; 

    Ich habe gerade festgestellt, dass ein Muster sogar Zugriffsspezifizierer wie public , wie im folgenden Beispiel gezeigt:

     template struct mixture : public Mixins ... //pattern = public Mixins { //code }; 

    In diesem Beispiel wird das Muster wie folgt erweitert:

     struct mixture__instantiated : public Mixin0, public Mixin1, .. public MixinN 

    Das heißt, die mixture öffentlich aus allen Basisklassen abgeleitet.

    Ich hoffe, das hilft.

    Das Folgende stammt aus dem Vortrag “Variadic Templates are Funadic” von Andrei Alexandrescu auf GoingNative 2012. Ich kann es für eine gute Einführung in variadische Vorlagen empfehlen.


    Es gibt zwei Dinge, die man mit einem Variadic Pack machen kann. Es ist möglich, sizeof...(vs) anzuwenden, um die Anzahl der Elemente zu erhalten und sie zu erweitern.

    Erweiterungsregeln

     Use Expansion Ts... T1, ..., Tn Ts&&... T1&&, ..., Tn&& x::z... x::z, ..., x::z x... x, ..., x func(5,vs)... func(5,v1), ..., func(5,vn) 

    Die Expansion verläuft nach innen. Wenn Sie zwei Listen in Lock-Step erweitern, müssen sie dieselbe Größe haben.

    Mehr Beispiele:

     gun(A::hun(vs)...); 

    Erweitert alle Ts in der Template-Argumentliste von A und dann wird die function hun mit allen vs .

     gun(A::hun(vs...)); 

    Erweitert alle Ts in der Template-Argumentliste von A und all vs als functionsargumente für hun .

     gun(A::hun(vs)...); 

    Erweitert die function hun mit Ts und vs in lock-step.

    Hinweis:

    Ts ist kein Typ und vs ist kein Wert! Sie sind Aliase für eine Liste von Typen / Werten. Beide Listen können möglicherweise leer sein. Beide gehorchen nur bestimmten Aktionen. Folgendes ist also nicht möglich:

     typedef Ts MyList; // error! Ts var; // error! auto copy = vs; // error! 

    Erweiterungsloci

    functionsargumente

     template  void fun(Ts... vs) 

    Initialisierungslisten

     any a[] = { vs... }; 

    Basisspezifizierer

     template  struct C : Ts... {}; template  struct D : Box... { /**/ }; 

    Mitgliedsinitialisierungslisten

     // Inside struct D template  D(Us... vs) : Box(vs)... {} 

    Tempa-Argumentlisten

     std::map m; 

    Wird nur kompiliert, wenn es eine mögliche Übereinstimmung für die Argumente gibt.

    Listen erfassen

     template  void fun(Ts... vs) { auto g = [&vs...] { return gun(vs...); } g(); } 

    Attributlisten

     struct [[ Ts... ]] IAmFromTheFuture {}; 

    Es ist in der Spezifikation, aber es gibt noch kein Attribut, das als Typ ausgedrückt werden kann.