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 );
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With