Что означает "... ..." токен?т.е. оператор двойного эллипса на пачке параметров - PullRequest
110 голосов
/ 11 апреля 2011

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

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

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

Итак, что означает этот токен?

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

Ответы [ 2 ]

78 голосов
/ 11 апреля 2011

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

  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 );
}
2 голосов
/ 26 мая 2016

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...