web-dev-qa-db-fra.com

Quelle est la signification du jeton "... ..."? c'est-à-dire opérateur double Ellipse sur pack de paramètres

En parcourant l'implémentation actuelle de gcc des nouveaux en-têtes C++ 11, je suis tombé sur le jeton "......". Vous pouvez vérifier que le code suivant compile bien [via ideone.com].

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

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

Alors, quelle est la signification de ce jeton?

edit: On dirait que SO rogné "......" dans le titre de la question en "...", je voulais vraiment dire "......". :)

110
Vitus

Chaque instance de cette bizarrerie est associée au cas d'une seule ellipse régulière.

  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; };

Je suppose que la double ellipse a une signification similaire à _ArgTypes..., ..., C'est-à-dire une expansion de modèle variadique suivie d'une liste de varargs de style C.

Voici un test soutenant cette théorie ... Je pense que nous avons un nouveau gagnant pour le pire pseudo-opérateur de tous les temps.

Edit: Cela semble être conforme. Le §8.3.5/3 décrit une manière de former la liste de paramètres comme

liste-de-déclaration-de-paramètresopt ...opt

Ainsi, la double-ellipse est formée par une liste de déclaration de paramètres se terminant par un pack de paramètres, suivie d'une autre ellipse.

La virgule est purement facultative; §8.3.5/4 dit

Là où la syntaxe est correcte et où "..." ne fait pas partie d'un déclarateur abstrait, ", ..." est synonyme de "...".

Ceci est dans un déclarateur abstrait, [edit] mais Johannes fait un bon point qu'ils font référence à un abstract-declarator dans une déclaration de paramètre. Je me demande pourquoi ils n'ont pas dit "une partie d'une déclaration de paramètre" et pourquoi cette phrase n'est pas qu'une note informative ...

De plus, va_begin() in <cstdarg> Nécessite un paramètre avant la liste des varargs, donc le prototype f(...) spécifiquement autorisé par C++ est inutile. Les renvois avec C99, c'est illégal en plein C. Donc, c'est très bizarre.

Note d'utilisation

Sur demande, voici une démonstration de la double Ellipse:

#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 );
}
78
Potatoswatter

sur vs2015, séparer la virgule est essentiel dans la version du modèle:

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

un exemple d'instanciation est:

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

salutations, FM.

3
Red.Wave