101 votes

Quelles sont les règles pour le jeton «... » dans le contexte de variadic template ?

En C++11 il y a variadic templates comme celui-ci:

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

Il y a quelques curiosités à ce sujet: L'expression std::forward<Args>(args)... utilise à la fois l' Args et args mais seulement un ... jeton. En outre, std::forward est un non-variadic template de fonction ne prenant qu'un paramètre de modèle et un argument. Quelles sont les règles de syntaxe pour que (en gros)? Comment peut-elle être généralisée?

Aussi: Dans la fonction de mise en œuvre les points de suspension (...) est à la fin de la manifestation d'intérêt. Est-il une raison que dans le modèle de la liste d'arguments et de la liste des paramètres de l'ellipse est dans le milieu?

103voto

Nawaz Points 148870

Dans le contexte de variadic template, les points de suspension en ... est utilisé pour décompresser le paramètre de modèle pack s'il apparaît sur la partie droite de l'expression (appel de cette expression motif pour un moment). La règle est que tout ce patron est sur le côté gauche de l' ... est répétée, l'déballé modèles (appeler expressions maintenant) sont séparés par des virgules ,.

Il peut être mieux compris par les quelques exemples. Supposons que vous avez ce modèle de fonction:

template<typename ...T>
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<T>(args)... );  //pattern = z<T>(args)
}

Maintenant, j'appelle cette fonction en passant T comme {int, char, short}, puis chaque appel de fonction est élargi:

g( arg0, arg1, arg2 );           
h( x(arg0), x(arg1), x(arg2) );
m( y(arg0, arg1, arg2) );
n( z<int>(arg0), z<char>(arg1), z<short>(arg2) );

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

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


Vous pouvez utiliser ... d'initialiser un tableau aussi comme:

struct data_info
{
     boost::any  data;
     std::size_t type_size;
};

std::vector<data_info> v{{args, sizeof(T)}...}; //pattern = {args, sizeof(T)}

qui est étendue à ceci:

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

Je viens de réaliser un modèle pourrait même inclure l'accès spécificateur comme public, comme le montre l'exemple suivant:

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

Dans cet exemple, le modèle est développé en tant que:

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

C'est, mixture dérive publiquement de toutes les classes de base.

Espérons que cela aide.

49voto

typ1232 Points 3309

Il y a deux choses qu'on peut faire avec un variadic pack. Il est possible d'appliquer sizeof...(vs) pour obtenir le nombre d'éléments et de les développer.

Extension des règles

Use            Expansion

Ts...          T1, ..., Tn
Ts&&...        T1&&, ..., Tn&&
x<Ts,Y>::z...  x<T1,Y>::z, ..., x<Tn,Y>::z
x<Ts&,Us>...   x<T1&,U1>, ..., x<Tn&,Un>
func(5,vs)...  func(5,v1), ..., func(5,vn)

L'Expansion du produit vers l'intérieur vers l'extérieur. Lors de l'extension des deux listes en lock-step, elles doivent avoir la même taille.

D'autres exemples:

gun(A<Ts...>::hun(vs)...);

Développe toutes Ts dans le modèle de la liste d'arguments d' A , puis la fonction hun obtient élargi à tous vs.

gun(A<Ts...>::hun(vs...));

Développe toutes Ts dans le modèle de la liste d'arguments d' A et tous vs que les arguments de la fonction pour hun.

gun(A<Ts>::hun(vs)...);

Développe la fonction hun avec Ts et vs en lock-step.

Note:

Ts n'est pas un type et vs n'est pas une valeur! Ils sont des alias pour une liste des types de valeurs. Une liste peut être vide. Les deux obéissent qu'à des actions spécifiques. Donc la suite n'est pas possible:

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

L'Expansion des loci

Les arguments de la fonction

template <typename... Ts>
void fun(Ts... vs)

Initialiseur de listes

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

La Base de prescripteurs

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

Membre de l'initialiseur de listes

// Inside struct D
template <typename... Us>
D(Us... vs) : Box<Ts>(vs)... {}

Avec des listes d'arguments

std::map<Ts...> m;

Ne compilera si il y a une correspondance possible pour les arguments.

La Capture de listes

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

Les listes d'attributs

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

C'est dans le cahier des charges, mais il n'y a pas d'attribut qui peut être exprimé comme un type, encore.


Ceci est pris à partir de la parole "Variadic Templates sont Funadic" par Andrei Alexandrescu à GoingNavive 2012. Je peux le recommander pour une bonne introdution sur les variadic templates.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X