En el contexto de la plantilla variadica, 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 esta expresión patrón por un momento). La regla es que cualquier patrón que esté en el lado izquierdo de ...
se repite; los patrones desempaquetados (llámelos expresiones ahora) están separados por comas ,
.
Puede entenderse mejor con algunos ejemplos. Suponga 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 pasando T
como {int, char, short}
, entonces cada llamada de función 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 n()
llamada a la función.
¡Note 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 incluso incluir un 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, mixture
deriva públicamente de todas las clases base.
Espero que ayude.
...
viene antes del identificador que se introduce. Al usar uno o ambos tipos de paquetes, el...
viene después del patrón de expresión para expandirse.