Каждый случай этой странности связан со случаем регулярного одиночного многоточия.
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; };
Я предполагаю, что двойной эллипс по своему значению аналогичен _ArgTypes..., ...
, то есть расширению вариативного шаблона, за которым следует список varargs в стиле C.
Вот тест в поддержку этой теории ... Я думаю, что у нас появился новый победитель для худшего псевдооператора за всю историю.
Редактировать: Похоже, это соответствует. §8.3.5 / 3 описывает один способ формирования списка параметров как
список объявлений параметров опт ... опт
Таким образом, двойной эллипс образуется списком объявлений параметров, заканчивающимся пакетом параметров, за которым следует еще один многоточие.
Запятая является чисто необязательной; §8.3.5 / 4 говорит
Если синтаксически правильно и где «...» не является частью абстрактного декларатора, «, ...» является синонимом «...».
Это в в объявителе-аннотации, [править] , но Йоханнес отмечает, что они ссылаются на декларатора-абстракция в объявлении-параметре. Интересно, почему они не сказали «часть объявления параметра», и почему это предложение не просто информативное примечание…
Кроме того, va_begin()
в <cstdarg>
требует параметр перед списком varargs, поэтому прототип f(...)
, специально разрешенный C ++, бесполезен. Перекрестные ссылки с C99 недопустимы на обычном C. Итак, это наиболее странно.
Замечание об использовании
По заказу вот демонстрация двойного эллипса:
#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 );
}