110

While browsing through gcc's current implementation of new C++11 headers, I stumbled upon "......" token. You can check, that the following code compiles fine [via ideone.com].

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

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

So, what is the meaning of this token?

edit: Looks like SO trimmed "......" in question title to "...", I did really mean "......" . :)

Patrick Fromberg
  • 1,215
  • 10
  • 35
Vitus
  • 11,413
  • 7
  • 32
  • 62

2 Answers2

79

Every instance of that oddity is paired with a case of a regular single ellipsis.

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

My guess is that the double ellipsis is similar in meaning to _ArgTypes..., ..., i.e. a variadic template expansion followed by a C-style varargs list.

Here's a test supporting that theory… I think we have a new winner for worst pseudo-operator ever.

Edit: This does appear to be conformant. §8.3.5/3 describes one way to form the parameter list as

parameter-declaration-listopt ...opt

So the double-ellipsis is formed by a parameter-declaration-list ending with a parameter pack, followed by another ellipsis.

The comma is purely optional; §8.3.5/4 does say

Where syntactically correct and where “...” is not part of an abstract-declarator, “, ...” is synonymous with “...”.

This is within an abstract-declarator, [edit] but Johannes makes a good point that they are referring to an abstract-declarator within a parameter-declaration. I wonder why they didn't say "part of a parameter-declaration," and why that sentence isn't just an informative note…

Furthermore, va_begin() in <cstdarg> requires a parameter before the varargs list, so the prototype f(...) specifically allowed by C++ is useless. Cross-referencing with C99, it is illegal in plain C. So, this is most bizarre.

Usage note

By request, here is a demonstration of the double ellipsis:

#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
  • 126,977
  • 21
  • 238
  • 404
  • Yes, that's right. T(U..., ...) however compiles fine, too; perhaps they wanted to save some space. :) – Vitus Apr 11 '11 at 18:34
  • 1
    But what would that mean? And how can the compiler tell where _ArgTypes end and some "extra" parameters start? – Bo Persson Apr 11 '11 at 18:35
  • 12
    @Bo Persson: `std::is_function`'s `value` must be true even if the function is C varargs one and because T(U...) is **not** match for such function, you need this madness. E.g. int f(int, char, ...) matches T(U......) exactly with T = int, U = {int, char} and the "..." varargs token. – Vitus Apr 11 '11 at 18:45
  • @Vitus - Ok, thanks I guess. I was just considering a new question "When is this useful?" to earn my first Tubleweed badge. No luck there, obviously. :-) – Bo Persson Apr 11 '11 at 18:52
  • 4
    "This *is* within an abstract-declarator" -> they mean not part of the abstract declarator of the last parameter of that same parameter type list. E.g `void (int...)` here, the `...` is not part of the abstract-declarator `int`, hence it is synonymous to `void(int, ...)`. If you would write `void(T...)` and `T` is a template parameter pack, `...` would be part of the abstract-declarator, and hence it would not be equivalent to `void(T, ...)`. – Johannes Schaub - litb Apr 11 '11 at 20:15
  • @Johannes: Ah, I think they could have been clearer about that. Does that sentence have any actual effect? It probably should be moved into the `[Note:]` block that follows. – Potatoswatter Apr 11 '11 at 21:10
  • Could you show some code that actually calls a function with this ...... notation, and what it means? – Clinton Apr 12 '11 at 03:03
  • I am not a c++ standard doc lawyer, Can you please tell me what do you mean by "within an **abstract** -declarator" – Mr.Anubis Dec 30 '11 at 17:34
  • @Mr.Anubis "abstract-declarator" is just a grammar production with little significance, except that it may include a `...`. It is "abstract" because it does not include any name to be declared, although in the context of a function declaration a non-abstract declarator (with a name) is also acceptable. If a name is supplied, though, it would go between the two ellipses. – Potatoswatter Dec 30 '11 at 17:50
  • 2
    "Furthermore, va_begin() in requires a parameter before the varargs list, so the prototype f(...) specifically allowed by C++ is useless." -- It's only useless if you want to know what arguments were passed. `f(...)` is used heavily as a fallback function overload in template metaprogramming, where this information is not necessary (and where the function doesn't even actually get called). –  Mar 19 '14 at 11:31
4

on vs2015 separating comma is essential in the template version:

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

an example instantiation is:

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

regards, FM.

Red.Wave
  • 1,427
  • 6
  • 8
  • I just noticed this too, it still happens. Bug report at https://developercommunity.visualstudio.com/content/problem/437260/incorrect-c3546-compiler-error.html. – egyik Jan 26 '19 at 22:42
  • Good to know. Any references or citations to standads about this? – Red.Wave Jan 27 '19 at 02:53
  • .سلام ببخشید نمیدانم – egyik Jan 30 '19 at 20:19
  • This is a public forum. Let people read what you think. PLZ keep native lang for private messages. سپاس. – Red.Wave Jan 31 '19 at 05:46
  • OK then. I'm no expert on the standard - I think that others have covered it in some detail above. If anyone cares to comment on the the Microsoft problem report then it might raise its priority. The report shows clang and gcc allowing what VC++ doesn't so I think we're probably on fairly strong ground. – egyik Jan 31 '19 at 22:11