No contexto do modelo variadic, as reticências ...
são usadas para descompactar o pacote de parâmetros do modelo se ele aparecer no lado direito de uma expressão (chame este padrão de expressão por um momento). A regra é que qualquer padrão que esteja no lado esquerdo de ...
é repetido - os padrões descompactados ( agora chame-os de expressões ) são separados por vírgula ,
.
Pode ser melhor compreendido por alguns exemplos. Suponha que você tenha este modelo de função:
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)
}
Agora, se eu chamar essa função passando T
como {int, char, short}
, cada uma das chamadas de função será expandida 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) );
No código que você postou, std::forward
segue o quarto padrão ilustrado pela n()
chamada de função.
Observe a diferença entre x(args)...
e y(args...)
acima!
Você também pode usar ...
para inicializar uma matriz 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 é expandido para este:
std::vector<data_info> v
{
{arg0, sizeof(int)},
{arg1, sizeof(char)},
{arg2, sizeof(short)}
};
Acabei de perceber que um padrão pode até incluir especificador de acesso public
, como mostrado no exemplo a seguir:
template<typename ... Mixins>
struct mixture : public Mixins ... //pattern = public Mixins
{
//code
};
Neste exemplo, o padrão é expandido como:
struct mixture__instantiated : public Mixin0, public Mixin1, .. public MixinN
Ou seja, mixture
deriva publicamente de todas as classes base.
Espero que ajude.
...
vem antes do identificador ser introduzido. Ao usar um ou ambos os tipos de pacotes, o...
vem após o padrão de expressão para expandir.