Quelle est la signification du jeton «……»? ie opérateur double ellipse sur pack de paramètres

110

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 se compile correctement [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 coupé "......" dans le titre de la question à "...", je voulais vraiment dire "......". :)

Vitus
la source
indice: il est ...suivi de ....
Alexandre C.
5
N'est-ce pas plus comme U...suivi par .... Très étrange néanmoins.
edA-qa mort-ora-y
1
Remarque: Cela peut être trouvé dans <functional>et <type_traits>, toujours dans le contexte d'une liste d'arguments de fonction à l'intérieur d'un paramètre de modèle.
Potatoswatter
le seul moyen que j'ai trouvé pour le faire coincé dans le titre était de mettre un espace entre les deux ... j'espère que cela le rendra plus clair pour les lecteurs.
Matthieu M.
@Matthieu M.: Merci, beaucoup mieux!
Vitus

Réponses:

79

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 un sens similaire à _ArgTypes..., ..., c'est- à -dire une expansion de modèle variadique suivie d'une liste de varargs de style C.

Voici un test qui soutient 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-déclaration-paramètre opt ... 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 «...».

C'est dans un abstrait déclarateur, [modifier] mais Johannes fait un bon point qu'ils font référence à un résumé-déclarateur dans un paramètre-déclaration. 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>requiert un paramètre avant la liste 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 );
}
Potatoswatter
la source
Oui c'est vrai. T (U ..., ...) compile également très bien; peut-être voulaient-ils économiser de l'espace. :)
Vitus
1
Mais qu'est-ce que cela signifierait? Et comment le compilateur peut-il dire où se termine _ArgTypes et où certains paramètres "supplémentaires" commencent?
Bo Persson
12
@Bo Persson: std::is_function's valuedoit être vrai même si la fonction est C varargs one et parce que T (U ...) ne correspond pas à une telle fonction, vous avez besoin de cette folie. Par exemple, int f (int, char, ...) correspond exactement à T (U ......) avec T = int, U = {int, char} et le jeton varargs "...".
Vitus
4
"Ceci est dans un déclarateur abstrait" -> ils signifient ne pas faire partie du déclarateur abstrait du dernier paramètre de cette même liste de types de paramètres. Par exemple, void (int...)ici, le ...ne fait pas partie du déclarateur abstrait int, il est donc synonyme de void(int, ...). Si vous écrivez void(T...)et Test un pack de paramètres de modèle, ...ferait partie du déclarateur abstrait, et par conséquent, il ne serait pas équivalent à void(T, ...).
Johannes Schaub - litb
2
"De plus, va_begin () dans <cstdarg> nécessite un paramètre avant la liste des varargs, donc le prototype f (...) spécifiquement autorisé par C ++ est inutile." - Ce n'est inutile que si vous voulez savoir quels arguments ont été passés. f(...)est largement utilisé comme surcharge de fonction de secours dans la métaprogrammation de modèle, où ces informations ne sont pas nécessaires (et où la fonction n'est même pas réellement appelée).
4

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.

Rouge.Vague
la source
J'ai juste remarqué ça aussi, ça arrive encore. Rapport de bogue sur developercommunity.visualstudio.com/content/problem/437260/… .
egyik le
Bon à savoir. Des références ou des citations à des standards à ce sujet?
Red.Wave
.سلام ببخشید نمیدانم
egyik
C'est un forum public. Laissez les gens lire ce que vous pensez. PLZ conserve la langue native pour les messages privés. سپاس.
Red.Wave
Alors ok. Je ne suis pas un expert de la norme - je pense que d'autres l'ont couvert en détail ci-dessus. Si quelqu'un souhaite commenter le rapport de problème de Microsoft, cela peut augmenter sa priorité. Le rapport montre clang et gcc autorisant ce que VC ++ ne fait pas, donc je pense que nous sommes probablement sur un terrain assez solide.
egyik