Quali sono le regole per il token “…” nel contesto dei modelli variadici?

In C ++ 11 ci sono modelli variadici come questo:

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

Ci sono alcune curiosità su questo: L’espressione std::forward(args)... usa sia Args che Args ma solo un token ... Inoltre std::forward è una funzione di template non variabile che prende solo un parametro template e un argomento. Quali sono le regole di syntax per quello (approssimativamente)? Come può essere generalizzato?

Inoltre: Nell’implementazione della funzione i puntini di sospensione ( ... ) si trovano alla fine dell’espressione di interesse. C’è un motivo per cui nell’elenco degli argomenti del modello e nell’elenco dei parametri i puntini di sospensione si trovano nel mezzo?

    Nel contesto del modello variadico, i puntini di sospensione ... vengono utilizzati per decomprimere il pacchetto di parametri del modello se appare sul lato destro di un’espressione (chiamare questo modello di espressione per un momento). La regola è che qualunque modello si trovi sul lato sinistro di ... viene ripetuto – i modelli scompattati (chiamali espressioni ora) sono separati da una virgola,.

    Può essere meglio compreso da alcuni esempi. Supponiamo di avere questo modello di funzione:

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

    Ora se chiamo questa funzione che passa T come {int, char, short} , allora ciascuna chiamata alla funzione è espansa come:

     g( arg0, arg1, arg2 ); h( x(arg0), x(arg1), x(arg2) ); m( y(arg0, arg1, arg2) ); n( z(arg0), z(arg1), z(arg2) ); 

    Nel codice che hai postato, std::forward segue il quarto pattern illustrato da n() chiamata di funzione.

    Notare la differenza tra x(args)... e y(args...) sopra!


    Puoi usare ... per inizializzare un array anche come:

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

    che è esteso a questo:

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

    Ho appena realizzato che un pattern potrebbe includere anche un identificatore di accesso come public , come mostrato nel seguente esempio:

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

    In questo esempio, il modello è espanso come:

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

    Cioè, la mixture deriva pubblicamente da tutte le classi base.

    Spero possa aiutare.

    Quanto segue è tratto dal talk “Variadic Templates is Funadic” di Andrei Alexandrescu a GoingNative 2012. Posso raccomandarlo per una buona introduzione sui modelli variadici.


    Ci sono due cose che si possono fare con un pacchetto variadico. È ansible applicare sizeof...(vs) per ottenere il numero di elementi ed espanderlo.

    Regole di espansione

     Use Expansion Ts... T1, ..., Tn Ts&&... T1&&, ..., Tn&& x::z... x::z, ..., x::z x... x, ..., x func(5,vs)... func(5,v1), ..., func(5,vn) 

    L’espansione procede verso l’interno. Quando si espandono due elenchi in blocco, devono avere la stessa dimensione.

    Altri esempi:

     gun(A::hun(vs)...); 

    Espande tutti i Ts nella lista degli argomenti del template di A e quindi la funzione hun viene espansa con tutti i vs

     gun(A::hun(vs...)); 

    Espande tutti i Ts nella lista degli argomenti del template di A e tutti vs come argomenti della funzione per hun .

     gun(A::hun(vs)...); 

    Espande la funzione hun con Ts e vs in lock-step.

    Nota:

    Ts non è un tipo e vs non è un valore! Sono alias per un elenco di tipi / valori. Ciascuna lista potrebbe essere potenzialmente vuota. Entrambi obbediscono solo ad azioni specifiche. Quindi il seguente non è ansible:

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

    Luoghi di espansione

    Argomenti di funzione

     template  void fun(Ts... vs) 

    Elenchi di inizializzatori

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

    Specificatori di base

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

    Elenchi di inizializzazione dei membri

     // Inside struct D template  D(Us... vs) : Box(vs)... {} 

    Tempi elenchi di argomenti

     std::map m; 

    Compilare solo se esiste una ansible corrispondenza per gli argomenti.

    Cattura elenchi

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

    Liste di attributi

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

    È nella specifica, ma non esiste ancora un attributo che possa essere express come un tipo.