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 Tcomo {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::forwardsigue 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, mixturederiva 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.