Qual è il significato del token "... ..."? cioè operatore con doppia ellissi sul pacchetto parametri


110

Durante la navigazione nell'attuale implementazione di gcc delle nuove intestazioni C ++ 11, sono incappato nel token "......". Puoi controllare che il codice seguente venga compilato correttamente [tramite ideone.com].

template <typename T>
struct X
{ /* ... */ };

template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
{ /* ... */ };

Allora, qual è il significato di questo token?

edit: Sembra così tagliato "......" nel titolo della domanda a "...", volevo davvero dire "......". :)


suggerimento: è ...seguito da ....
Alexandre C.

5
Non è più come U...seguito da .... Ciononostante molto strano.
edA-qa mort-ora-y

1
Nota: questo può essere trovato in <functional>e <type_traits>, sempre nel contesto di un elenco di argomenti di funzione all'interno di un parametro di modello.
Potatoswatter

l'unico modo che ho trovato per farlo rimanere bloccato nel titolo è stato quello di mettere uno spazio in mezzo ... spero che lo renda più chiaro per i lettori.
Matthieu M.

@ Matthieu M .: Grazie, molto meglio!
Vitus

Risposte:


79

Ogni istanza di quella stranezza è abbinata a un caso di puntini di sospensione singoli regolari.

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
    { typedef _Res result_type; };

La mia ipotesi è che la doppia ellissi abbia un significato simile a _ArgTypes..., ..., cioè un'espansione del modello variadica seguita da un elenco di variabili in stile C.

Ecco un test a sostegno di questa teoria ... Penso che abbiamo un nuovo vincitore per il peggior pseudo-operatore di sempre.

Modifica: questo sembra essere conforme. §8.3.5 / 3 descrive un modo per formare l'elenco dei parametri come

lista-dichiarazione-parametri opt ... opz

Quindi la doppia ellissi è formata da una lista di dichiarazione di parametri che termina con un pacchetto di parametri, seguita da un'altra ellissi.

La virgola è puramente facoltativa; §8.3.5 / 4 dice

Dove sintatticamente corretto e dove "..." non fa parte di un dichiaratore astratto, ", ..." è sinonimo di "...".

Questo è all'interno di un dichiaratore astratto, [modifica] ma Johannes sottolinea bene che si riferiscono a un dichiaratore astratto all'interno di una dichiarazione di parametri. Mi chiedo perché non abbiano detto "parte di una dichiarazione di parametri" e perché quella frase non sia solo una nota informativa ...

Inoltre, va_begin()in <cstdarg>richiede un parametro prima dell'elenco varargs, quindi il prototipo f(...)specificamente consentito da C ++ è inutile. Riferimento incrociato con C99, è illegale in pianura C. Quindi, questo è molto bizzarro.

Nota di utilizzo

A richiesta, ecco una dimostrazione della doppia ellissi:

#include <cstdio>
#include <string>

template< typename T >
T const &printf_helper( T const &x )
    { return x; }

char const *printf_helper( std::string const &x )
    { return x.c_str(); }

template< typename ... Req, typename ... Given >
int wrap_printf( int (*fn)( Req... ... ), Given ... args ) {
    return fn( printf_helper( args ) ... );
}

int main() {
    wrap_printf( &std::printf, "Hello %s\n", std::string( "world!" ) );
    wrap_printf( &std::fprintf, stderr, std::string( "Error %d" ), 5 );
}

Sì, è giusto. Anche T (U ..., ...) viene compilato bene; forse volevano risparmiare spazio. :)
Vitus

1
Ma cosa significherebbe? E come può il compilatore dire dove finiscono _ArgTypes e iniziano alcuni parametri "extra"?
Bo Persson

12
@Bo Persson: std::is_functions' valuedeve essere vero anche se la funzione è C varargs uno e perché T (U ...) è non corrisponde a tale funzione, è necessario questa follia. Ad esempio int f (int, char, ...) corrisponde a T (U ......) esattamente con T = int, U = {int, char} e il token "..." varargs.
Vitus

4
"Questo è all'interno di un dichiaratore astratto" -> significa che non fa parte del dichiaratore astratto dell'ultimo parametro di quella stessa lista di tipi di parametri. Ad esempio void (int...), qui ...non fa parte del dichiaratore astratto int, quindi è sinonimo di void(int, ...). Se si scrivesse void(T...)ed Tè un pacchetto di parametri del modello, ...farebbe parte del dichiaratore astratto e quindi non sarebbe equivalente a void(T, ...).
Johannes Schaub - litb

2
"Inoltre, va_begin () in <cstdarg> richiede un parametro prima dell'elenco varargs, quindi il prototipo f (...) specificamente consentito da C ++ è inutile." - È inutile solo se vuoi sapere quali argomenti sono stati fatti. f(...)viene utilizzato pesantemente come sovraccarico della funzione di fallback nella metaprogrammazione dei modelli, dove queste informazioni non sono necessarie (e dove la funzione non viene nemmeno chiamata).

4

su vs2015 la virgola di separazione è essenziale nella versione del modello:

    template <typename T, typename ... U>
    struct X<T(U...,...)> {};// this line is the important one

un esempio di istanziazione è:

    X<int(int...)> my_va_func;

saluti, FM.


Ho appena notato anche questo, succede ancora. Segnalazione di bug su Developercommunity.visualstudio.com/content/problem/437260/… .
egyik

Buono a sapersi. Eventuali riferimenti o citazioni a standard su questo?
Red.Wave

.سلام ببخشید نمیدانم
egyik

Questo è un forum pubblico. Lascia che le persone leggano quello che pensi. PLZ mantiene la lingua nativa per i messaggi privati. سپاس.
Red.Wave

Va bene allora. Non sono un esperto dello standard, penso che altri lo abbiano trattato in dettaglio sopra. Se qualcuno si preoccupa di commentare il rapporto sul problema di Microsoft, potrebbe aumentare la sua priorità. Il rapporto mostra clang e gcc che consentono ciò che VC ++ non fa, quindi penso che probabilmente siamo su un terreno abbastanza solido.
egyik
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.