В чем смысл "......" токена? то есть двойной эллипсовый оператор на пачке параметров

Во время просмотра gcc текущей реализации новых заголовков С++ 11 я наткнулся на токен "......" . Вы можете проверить, что следующий код компилируется отлично [через ideone.com].

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

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

Итак, в чем смысл этого токена?

edit: Похоже, что урезано "......" в вопросе "...", я действительно имел в виду "......" .:)

Ответ 1

Каждый экземпляр этой нечетности сопряжен с случаем регулярного одиночного эллипса.

  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 описывается один из способов формирования списка параметров как

параметр-декларация-список opt... opt

Таким образом, двойной эллипс формируется списком объявления параметров, заканчивающимся пакетом параметров, а затем другим эллипсисом.

Запятая является чисто необязательной; В §8.3.5/4 говорится

Где синтаксически корректно и где "..." не является частью абстрактного-декларатора, ",..." является синонимом "...".

Это находится в абстрактном-деклараторе, [edit], но Йоханнес хорошо указывает, что они ссылаются на абстрактно-декларатор в декларации параметра. Интересно, почему они не сказали "часть декларации параметра", и почему это предложение не просто информативное примечание...

Кроме того, va_begin() в <cstdarg> требует параметра перед списком varargs, поэтому прототип f(...), специально разрешенный С++, бесполезен. Перекрестная ссылка на 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 );
}

Ответ 2

в vs2015 разделение запятой имеет важное значение в версии шаблона:

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

пример создания экземпляра:

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

С уважением, FM.