Search code examples
c++c++11variadic-templatesvariadic-functions

What is the meaning of "... ..." token? i.e. double ellipsis operator on parameter pack


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 godbolt.org].

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 "......" . :)


Solution

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