Каковы 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 точек?
Ответы
Ответ 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 , ...
и говорит:
[...] Где синтаксически правильно и где "..." не является частью абстрактный-декларатор, ",..." является синонимом "...". [...]