Подтвердить что ты не робот

Каковы 6 точек в пакетах параметров шаблонов?

Рассматривая этот вопрос, я оказался на справочном сайте cpp где я заметил странный и новый для меня синтаксис:

template<class Ret, class... Args>
struct is_function<Ret(Args......)volatile &&> : std::true_type {};

Да, 6 точек! Первоначально я думал, что это была опечатка, но после проверки libstdС++ source снова это было, например, в строке 444:

template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) volatile &&> : public true_type { };

Является ли это допустимым синтаксисом? Точечная точка, используется для упаковки и распаковки пакетов параметров? Что делают 6 точек?

4b9b3361

Ответ 1

В этом случае они предназначены для разных целей. Первый - для расширения пакета параметров, а второй - для списков переменных аргументов. Это конкретное объявление должно обрабатывать функции, которые принимают некоторые регулярные параметры плюс список переменных аргументов.

Разница между временем выполнения и изменчивостью во времени компиляции. Специальная функция, которая принимает переменное количество аргументов во время выполнения. Это единственная функция, которая может обрабатывать переменное количество аргументов от вызывающего:

void f(int x,...) // equivalent to void f(int x ...)
{
    // Do some run-time logic here to determine what to
    // do with parameters after x.
}

Это отличается от понятия, что мы хотим иметь шаблон, который использует множество функций с различными параметрами, которые известны во время компиляции. Например, мы могли бы определить шаблон функции, который принимает указатель на функцию и позволяет изменять количество и типы аргументов:

template <typename... Args>
void g(void (*function_ptr)(Args...)) 
{ 
    // We can do logic here to call function_ptr with the proper
    // number of arguments.
}

Учитывая эти функции:

void f1(int);
void f2(int,float);

Вы можете вызвать g любым из них:

g(f1); // fine
g(f2); // also fine

Однако

g(f); // error

Компилятор не знал, что использовать для пакета параметров Args в g.

Ответ 2

Почему libstdc++ использует ... ... в реализации is_function? Если мы проверим раздел cppreference для std:: is_function, он дает примерную реализацию и говорит для первого случая ... ...:

// specialization for variadic functions such as std::printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};

поэтому нам нужен второй набор ... для соответствия переменной функции, такой как printf:

           Comma optional as per 8.3.5 [dcl.fct] 
           |
           v
Ret(Args... ...)
        ^   ^
        |   |
        Match a function with a variable number of arguments
            |
            and the function is a variadic function

Обратите внимание, что мы имеем такие функции, как fprintf, что два аргумента перед переменными членами, и нам также нужно их сопоставить. Действительно, если мы используем эту реализацию и пытаемся сопоставить printf без специализации ... ..., тогда она терпит неудачу видеть ее в прямом эфире.

Этот угол языка рассматривается в этом сообщении С++ 11 шесть точек:

Я набрасывался на другой день и обнаружил эту симпатичную маленькую странность:

template <typename... Args>
void foo(Args......);

Как оказалось,...... может быть полностью допустимым С++ 11. Это то, что происходит, когда обратная совместимость смешивается с новой жарой.

//Все они эквивалентны.

template <typename... Args> void foo1(Args......);
template <typename... Args> void foo2(Args... ...);
template <typename... Args> void foo3(Args..., ...);

Надеюсь, последний показывает, что здесь происходит. [...]

Почему это валлиль? Мы можем видеть, что , ... является синонимом ... из стандартного раздела проекта С++ 11 8.3.5 [dcl.fct], который имеет следующую грамматику:

parameter-declaration-clause:
  parameter-declaration-listopt...opt
  parameter-declaration-list , ...

и говорит:

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