Jakie jest znaczenie tokena „……”? tj. operator podwójnego wielokropka w pakiecie parametrów


110

Przeglądając aktualną implementację nowych nagłówków C ++ 11 w gcc, natknąłem się na token „......”. Możesz sprawdzić, czy poniższy kod kompiluje się dobrze [przez ideone.com].

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

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

Więc jakie jest znaczenie tego tokena?

edycja: Wygląda na tak przycięty „......” w tytule pytania do „…”, naprawdę miałem na myśli „......”. :)


wskazówka: ...następuje po nim ....
— Alexandre C.

5
Czy nie jest to bardziej jak U...następuje .... Niemniej jednak bardzo dziwne.
— edA-qa mort-ora-y

1
Uwaga: można to znaleźć w programie <functional>i <type_traits>, zawsze w kontekście listy argumentów funkcji wewnątrz parametru szablonu.
— Potatoswatter

Jedynym sposobem, w jaki utknąłem w tytule, było wstawienie spacji między ... mam nadzieję, że uczyni to bardziej przejrzystym dla czytelników.
— Matthieu M.

@Matthieu M .: Dzięki, dużo lepiej!
— Vitus

Odpowiedzi:


79

Każde wystąpienie tej osobliwości jest powiązane z przypadkiem zwykłej pojedynczej wielokropka.

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

Domyślam się, że podwójny wielokropek ma podobne znaczenie _ArgTypes..., ..., np. Wariadyczne rozwinięcie szablonu, po którym następuje lista varargs w stylu C.

Oto test potwierdzający tę teorię… Myślę, że mamy nowego zwycięzcę dla najgorszego pseudo-operatora wszechczasów.

Edycja: wydaje się, że jest to zgodne. W §8.3.5 / 3 opisano jeden ze sposobów tworzenia listy parametrów jako

lista-deklaracji parametrów opt ... opt

Tak więc podwójny wielokropek jest tworzony przez listę deklaracji parametrów kończącą się pakietem parametrów, po której następuje kolejny wielokropek.

Przecinek jest całkowicie opcjonalny; §8.3.5 / 4 mówi

Tam, gdzie składniowo poprawne i gdzie „…” nie jest częścią deklaratora abstrakcji, „,…” jest synonimem „…”.

Dzieje się to w ramach abstrakcyjnego-deklaratora, [edytuj], ale Johannes dobrze zauważa, że ​​odnoszą się one do abstrakcyjnego-deklaratora w deklaracji parametru. Zastanawiam się, dlaczego nie powiedzieli „część deklaracji parametru” i dlaczego to zdanie nie jest tylko informacją…

Ponadto va_begin()in <cstdarg>wymaga parametru przed listą varargs, więc prototyp f(...)wyraźnie dozwolony przez C ++ jest bezużyteczny. Powiązanie z C99 jest nielegalne w zwykłym C. To jest najbardziej dziwne.

Uwaga dotycząca użytkowania

Na życzenie przedstawiam podwójną wielokropek:

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

Tak to prawda. T (U ..., ...) jednak również kompiluje się dobrze; być może chcieli zaoszczędzić trochę miejsca. :)
— Vitus

1
Ale co by to oznaczało? W jaki sposób kompilator może stwierdzić, gdzie kończą się _ArgTypes, a zaczynają się niektóre „dodatkowe” parametry?
— Bo Persson

12
@Bo Persson: std::is_functions valuemusi być prawdziwe, nawet jeśli funkcja jest jedną z C varargs i ponieważ T (U ...) nie pasuje do takiej funkcji, potrzebujesz tego szaleństwa. Np. Int f (int, char, ...) dopasowuje T (U ......) dokładnie z T = int, U = {int, char} i tokenem varargs „...”.
— Vitus

4
„To jest wewnątrz abstrakcyjnego-deklaratora” -> nie są częścią abstrakcyjnego deklaratora ostatniego parametru tej samej listy typów parametrów. Np. void (int...)Tutaj, ...nie jest częścią abstrakcyjnego-deklaratora int, stąd jest synonimem void(int, ...). Jeśli napisałbyś void(T...)i Tjest pakietem parametrów szablonu, ...byłby częścią abstrakcyjnego deklaratora, a zatem nie byłby równoważny z void(T, ...).
— Johannes Schaub - litb

2
„Co więcej, va_begin () w <cstdarg> wymaga parametru przed listą varargs, więc prototyp f (...) specjalnie dozwolony przez C ++ jest bezużyteczny.” - Nie ma sensu tylko wtedy, gdy chcesz wiedzieć, jakie argumenty zostały przekazane. f(...)jest często używany jako przeciążenie funkcji rezerwowej w metaprogramowaniu szablonów, gdzie ta informacja nie jest konieczna (a funkcja nawet nie jest wywoływana).

4

w vs2015 przecinek oddzielający jest niezbędny w wersji szablonu:

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

przykładowa instancja to:

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

pozdrawiam, FM.


Właśnie to zauważyłem, nadal to się dzieje. Raport o błędzie na developercommunity.visualstudio.com/content/problem/437260/… .
— egyik

Dobrze wiedzieć. Jakieś odniesienia lub cytaty ze stanowisk na ten temat?
— Red.Wave

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

To jest forum publiczne. Pozwól ludziom przeczytać, co myślisz. PLZ zachowuje język ojczysty dla prywatnych wiadomości. سپاس.
— Red.Wave

OK. Nie jestem ekspertem od standardu - myślę, że inni omówili to trochę powyżej. Jeśli komuś zależy na skomentowaniu raportu o problemie firmy Microsoft, może to podnieść jego priorytet. Raport pokazuje, że clang i gcc pozwalają na to, czego VC ++ nie robi, więc myślę, że prawdopodobnie jesteśmy na dość mocnym gruncie.
— egyik
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.