Quelles sont les règles pour le jeton «…» dans le contexte des modèles variadiques?

En C ++ 11, il existe des modèles variadiques comme celui-ci:

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

Il y a quelques curiosités à ce sujet: L’expression std::forward(args)... utilise à la fois Args et args mais un seul ... token. De plus, std::forward est une fonction de modèle non variadique ne prenant qu’un seul paramètre de modèle et un seul argument. Quelles sont les règles de syntaxe pour cela (grossièrement)? Comment peut-il être généralisé?

Aussi: Dans la fonction implémentation, les points de suspension ( ... ) sont à la fin de l’expression d’intérêt. Y a-t-il une raison pour laquelle, dans la liste des arguments du modèle et la liste des parameters, les points de suspension sont au milieu?

Dans le contexte du modèle variadique, les points de suspension ... permettent de décompresser le pack de parameters du modèle s’il apparaît à droite d’une expression (appelez ce modèle d’ expression un instant). La règle est que quel que soit le motif à gauche de ... est répété – les motifs décompressés (appelez-les maintenant expressions ) sont séparés par une virgule,.

On peut mieux comprendre par quelques exemples. Supposons que vous ayez ce modèle de fonction:

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

Maintenant, si j’appelle cette fonction en passant T comme {int, char, short} , alors chaque appel de fonction est développé comme suit:

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

Dans le code que vous avez posté, std::forward suit le quasortingème modèle illustré par l’appel de la fonction n() .

Notez la différence entre x(args)... et y(args...) ci-dessus!


Vous pouvez utiliser ... pour initialiser un tableau aussi comme:

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

qui est élargi à ceci:

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

Je viens de réaliser qu’un modèle peut même inclure un spécificateur d’access tel que public , comme le montre l’exemple suivant:

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

Dans cet exemple, le modèle est développé comme suit:

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

C’est-à-dire que le mixture dérive publiquement de toutes les classes de base.

J’espère que cela pourra aider.

Ce qui suit est tiré de la conversation “Modèles Variadic sont Funadic” par Andrei Alexandrescu à GoingNative 2012. Je peux le recommander pour une bonne introduction sur les modèles variadiques.


On peut faire deux choses avec un pack variadic. Il est possible d’appliquer sizeof...(vs) pour obtenir le nombre d’éléments et le développer.

Règles d’extension

 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) 

L’expansion se poursuit vers l’extérieur. Lorsque vous développez deux listes en mode pas à pas, elles doivent avoir la même taille.

Plus d’exemples:

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

Développe tous les Ts dans la liste des arguments du modèle de A , puis la fonction hun est développée avec tous les vs

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

Développe tous les Ts dans la liste des arguments du modèle A et tous les vs tant qu’arguments de la fonction pour hun .

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

Développe la fonction hun avec Ts et vs dans le pas de locking.

Remarque:

Ts n’est pas un type et vs n’est pas une valeur! Ce sont des alias pour une liste de types / valeurs. Chaque liste peut être potentiellement vide. Les deux n’obéissent qu’à des actions spécifiques. Donc, ce qui suit n’est pas possible:

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

Lieux d’expansion

Arguments de fonction

 template  void fun(Ts... vs) 

Listes d’initialisation

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

Spécificateurs de base

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

Listes d’initialisation des membres

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

Tempate listes d’arguments

 std::map m; 

Ne comstackra que s’il existe une correspondance possible pour les arguments.

Capturer des listes

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

Listes d’atsortingbuts

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

C’est dans la spécification, mais il n’y a pas encore d’atsortingbut pouvant être exprimé en tant que type.