Was bedeutet der Token „……“? dh doppelter Auslassungsoperator im Parameterpaket

110

Beim Durchsuchen der aktuellen Implementierung neuer C ++ 11-Header durch gcc bin ich auf das Token "......" gestoßen. Sie können überprüfen, ob der folgende Code gut kompiliert werden kann [via ideone.com].

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

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

Was bedeutet dieses Token?

edit: Sieht so aus, als hätte "......" im Fragentitel auf "..." gekürzt, ich meinte wirklich "......". :) :)

Vitus
quelle
Hinweis: es ...folgt ....
Alexandre C.
5
Ist es nicht eher wie U...gefolgt von .... Trotzdem sehr seltsam.
edA-qa mort-ora-y
1
Hinweis: Dies kann in <functional>und <type_traits>immer im Kontext einer Funktionsargumentliste innerhalb eines Vorlagenparameters gefunden werden.
Potatoswatter
Die einzige Möglichkeit, es im Titel festzuhalten, bestand darin, ein Leerzeichen dazwischen zu setzen ... ich hoffe, es macht es für die Leser klarer.
Matthieu M.
@Matthieu M.: Danke, viel besser!
Vitus

Antworten:

79

Jede Instanz dieser Kuriosität ist mit einem Fall einer regulären einzelnen Ellipse gepaart.

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

Ich vermute, dass die doppelte Ellipse eine ähnliche Bedeutung hat wie _ArgTypes..., ...eine variable Vorlagenerweiterung, gefolgt von einer Varargs-Liste im C-Stil.

Hier ist ein Test , der diese Theorie unterstützt… Ich denke, wir haben einen neuen Gewinner für den schlechtesten Pseudooperator aller Zeiten.

Bearbeiten: Dies scheint konform zu sein. §8.3.5 / 3 beschreibt eine Möglichkeit, die Parameterliste zu bilden als

Parameterdeklarationsliste opt ... opt

Die Doppelellipse wird also durch eine Parameterdeklarationsliste gebildet, die mit einem Parameterpaket endet, gefolgt von einer weiteren Ellipse.

Das Komma ist rein optional; §8.3.5 / 4 sagt

Wo syntaktisch korrekt und wo "..." nicht Teil eines Abstract-Deklarators ist, ist ", ..." gleichbedeutend mit "...".

Dies ist innerhalb eines abstrakten Deklarators, [Bearbeiten], aber Johannes macht einen guten Punkt, dass sie sich auf einen abstrakten Deklarator innerhalb einer Parameterdeklaration beziehen. Ich frage mich, warum sie nicht "Teil einer Parameterdeklaration" gesagt haben und warum dieser Satz nicht nur eine informative Notiz ist ...

Weiterhin va_begin()in <cstdarg>erfordert einen Parameter , bevor die Liste varargs, so dass der Prototyp f(...)speziell von C ++ erlaubt ist nutzlos. Querverweise mit C99 sind in der Ebene C illegal. Das ist also höchst bizarr.

Verwendungshinweis

Auf Anfrage finden Sie hier eine Demonstration der doppelten 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 );
}
Kartoffelklatsche
quelle
Ja, das ist richtig. T (U ..., ...) kompiliert jedoch auch gut; Vielleicht wollten sie etwas Platz sparen. :)
Vitus
1
Aber was würde das bedeuten? Und wie kann der Compiler feststellen, wo _ArgTypes endet und einige "zusätzliche" Parameter beginnen?
Bo Persson
12
@Bo Persson: std::is_function's valuemuss wahr sein, auch wenn die Funktion C varargs eins ist und weil T (U ...) für eine solche Funktion nicht übereinstimmt, brauchen Sie diesen Wahnsinn. ZB stimmt int f (int, char, ...) genau mit T (U ......) mit T = int, U = {int, char} und dem varargs-Token "..." überein.
Vitus
4
"Dies ist innerhalb eines abstrakten Deklarators" -> sie bedeuten, dass sie nicht Teil des abstrakten Deklarators des letzten Parameters derselben Parametertypliste sind. ZB void (int...)ist das ...hier nicht Teil des Abstract-Deklarators int, daher ist es auch ein Synonym für void(int, ...). Wenn Sie schreiben würden void(T...)und Tein Template-Parameterpaket sind, ...wäre dies Teil des Abstract-Deklarators und daher nicht gleichbedeutend mit void(T, ...).
Johannes Schaub - litb
2
"Außerdem benötigt va_begin () in <cstdarg> einen Parameter vor der varargs-Liste, sodass der von C ++ speziell zugelassene Prototyp f (...) unbrauchbar ist." - Es ist nur nutzlos, wenn Sie wissen möchten, welche Argumente übergeben wurden. f(...)wird häufig als Überlastung von Fallback-Funktionen bei der Metaprogrammierung von Vorlagen verwendet, wenn diese Informationen nicht erforderlich sind (und wenn die Funktion nicht einmal aufgerufen wird).
4

In vs2015 ist das Trennen von Kommas in der Vorlagenversion unerlässlich:

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

Eine beispielhafte Instanziierung ist:

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

Grüße, FM.

Red.Wave
quelle
Ich habe das auch gerade bemerkt, es passiert immer noch. Fehlerbericht unter Developercommunity.visualstudio.com/content/problem/437260/… .
Egyik
Gut zu wissen. Irgendwelche Verweise oder Zitate auf Standads dazu?
Red.Wave
.سلام ببخشید نمیدانم
egyik
Dies ist ein öffentliches Forum. Lassen Sie die Leute lesen, was Sie denken. PLZ behält native Sprache für private Nachrichten. سپاس.
Red.Wave
OK dann. Ich bin kein Experte für den Standard - ich denke, dass andere ihn oben ausführlich behandelt haben. Wenn jemand den Microsoft-Problembericht kommentieren möchte, erhöht er möglicherweise seine Priorität. Der Bericht zeigt, wie clang und gcc zulassen, was VC ++ nicht zulässt. Ich denke, wir befinden uns wahrscheinlich auf einem ziemlich starken Boden.
Egyik