Cada instância dessa estranheza é emparelhada com um caso de uma única elipse regular.
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; };
Meu palpite é que a elipse dupla é semelhante em significado a _ArgTypes..., ...
, ou seja, uma expansão de modelo variadic seguida por uma lista de varargs de estilo C.
Aqui está um teste que apóia essa teoria ... Acho que temos um novo vencedor para o pior pseudo-operador de todos os tempos.
Edit: Isso parece estar em conformidade. §8.3.5 / 3 descreve uma maneira de formar a lista de parâmetros como
parâmetro-declaração-lista opt ... opt
Assim, a elipse dupla é formada por uma lista de declaração de parâmetros terminando com um pacote de parâmetros, seguido por outras reticências.
A vírgula é puramente opcional; §8.3.5 / 4 diz
Onde sintaticamente correto e onde “...” não faz parte de um declarador abstrato, “, ...” é sinônimo de “...”.
Isso está dentro de um declarador abstrato, [editar] mas Johannes afirma que eles estão se referindo a um declarador abstrato dentro de uma declaração de parâmetro. Eu me pergunto por que eles não disseram "parte de uma declaração de parâmetro" e por que essa frase não é apenas uma nota informativa ...
Além disso, va_begin()
in <cstdarg>
requer um parâmetro antes da lista de varargs, de modo que o protótipo f(...)
especificamente permitido por C ++ é inútil. A referência cruzada com C99 é ilegal na planície C. Então, isso é muito bizarro.
Nota de uso
A pedido, aqui está uma demonstração da elipse dupla:
#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 );
}
...
seguido por...
.