c++ c++11 variadic-templates

c++ - ¿Cuáles son las reglas para el token "..." en el contexto de plantillas variadic?



c++11 variadic-templates (2)

En el contexto de la plantilla variadic, la elipsis ... se usa para descomprimir el paquete de parámetros de la plantilla si aparece en el lado derecho de una expresión (llame a este patrón de expresión por un momento). La regla es que cualquier patrón que esté en el lado izquierdo de ... se repite: los patrones desempaquetados (ahora se llaman expresiones ) están separados por comas,.

Se puede entender mejor con algunos ejemplos. Supongamos que tiene esta plantilla de función:

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

Ahora si llamo a esta función que pasa T como {int, char, short} , cada una de las llamadas de funciones se expande como:

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

En el código que publicó, std::forward sigue el cuarto patrón ilustrado por la llamada a la función n() .

¡Observe la diferencia entre x(args)... y y(args...) arriba!

Puede usar ... para inicializar una matriz también como:

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

que se expande a esto:

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

Me acabo de dar cuenta de que un patrón podría incluir especificador de acceso como public , como se muestra en el siguiente ejemplo:

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

En este ejemplo, el patrón se expande como:

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

Es decir, la mixture deriva públicamente de todas las clases base.

Espero que ayude.

En C ++ 11 hay plantillas variadas como esta:

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

Hay algunas curiosidades sobre esto: La expresión std::forward<Args>(args)... usa tanto Args como args pero solo un ... token. Además, std::forward es una función de plantilla no variadica que toma solo un parámetro de plantilla y un argumento. ¿Cuáles son las reglas de sintaxis para eso (más o menos)? ¿Cómo se puede generalizar?

Además: en la implementación de la función, la elipsis ( ... ) está al final de la expresión de interés. ¿Hay alguna razón por la que en la lista de argumentos de la plantilla y en la lista de parámetros, la elipsis esté en el medio?


Lo siguiente está tomado de la charla "Variadic Templates are Funadic" de Andrei Alexandrescu en GoingNative 2012. Lo puedo recomendar para una buena introducción sobre plantillas variadic.

Hay dos cosas que uno puede hacer con un paquete variadic. Es posible aplicar sizeof...(vs) para obtener el número de elementos y expandirlo.

Reglas de expansión

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)

La expansión procede hacia adentro y hacia afuera. Al expandir dos listas en lock-step, deben tener el mismo tamaño.

Más ejemplos:

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

Expande todos los Ts en la lista de argumentos de la plantilla de A y luego la función hun se expande con todos los vs

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

Expande todos los Ts en la lista de argumentos de la plantilla de A y todos los vs como los argumentos de la función para hun .

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

Expande la función hun con Ts y vs en lock-step.

Nota:

Ts no es un tipo y vs no es un valor! Son alias para una lista de tipos / valores. Cualquiera de las listas puede estar potencialmente vacía. Ambos obedecen solo acciones específicas. Entonces lo siguiente no es posible:

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

Loci de expansión

Argumentos de función

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

Listas de inicializadores

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

Especificadores de base

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

Listas de inicialización de miembros

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

Listas de argumentos de Tempate

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

Solo compilará si hay una posible coincidencia para los argumentos.

Listas de captura

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

Listas de atributos

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

Está en la especificación, pero aún no hay ningún atributo que se pueda expresar como un tipo.