Вариативный шаблон: кандидат ожидает 1 аргумент, предоставлено 0 (ошибка вывода)

Посмотрите на этот фрагмент кода

template<class T> 
void print(T var)
{
    std::cout << var << " ";
}
 
template<class... Args> 
void Variadic(Args... args)
{
    print(args...);
}

int main()
{
     Variadic();
}

Когда я компилирую, он говорит:

кандидат: шаблон void print(T)

кандидат ожидает 1 аргумент, предоставлено 0

И он прав. На самом деле я не предоставил никаких аргументов в пакете параметров.

Но почему тогда этот код компилируется?

template<class T> 
void print(T var)
{
    std::cout << var << " ";
}
 
template<class... Args> 
void Variadic(Args... args)
{
    auto x = {0, (print(args), 0)...};
}

int main()
{
     Variadic();
}

Первое, что я делаю, это вставляю первый 0 в список initializer_list‹›.

Хорошо, теперь идем дальше: компилятор видит

(print(args), 0)...

Он пытается вызвать print()… о, подождите… Пакет параметров пуст, а функция print() принимает 1 параметр.

Почему тогда он оценивается как auto x = {0};?

Почему компилятор не выдает ту же ошибку, что и раньше?


person gedamial    schedule 23.06.2016    source источник


Ответы (2)


Вы неправильно понимаете, как работает оператор раскрытия .... В вашем примере, когда args - это пустой пакет, (print(args), 0)... расширяется до нуля, а не print().

Если бы args было задано как x, оно расширилось бы до print(x), 0.

Если бы args было задано как x, y, оно расширилось бы до (print(x), 0), (print(y), 0).

и Т. Д.

По сути, он расширяет все выражение, содержащее args, и применяется к нему, а не только сам бит args.

Из стандартного [temp.variadic]:

  1. Расширение пакета состоит из шаблона и многоточия, реализация которых приводит к нулю или более экземплярам шаблона в списке. Форма паттерна зависит от контекста, в котором происходит расширение.

...

  1. Создание экземпляра расширения пакета, который не является ни выражением sizeof..., ни выражением fold, создает список E1, E2, ..., EN , где N — количество элементов в параметрах расширения пакета. Каждый Ei создается путем создания экземпляра шаблона и замены каждого параметра расширения пакета его i-м элементом.
person Smeeheey    schedule 23.06.2016
comment
Итак, если я правильно понял, поскольку пакет параметров пуст, мой (print(args), 0)... ничего не оценивает? Так что я получаю auto x = {0}; (ноль, который вы видите, это первый, который я нажал) - person gedamial; 23.06.2016

Согласно стандартным шаблонам C++ 14.5.3/p4 Variadic [temp.variadic] (Emphasis Mine):

Расширение пакета состоит из шаблона и многоточия, создание которых создает ноль или более экземпляров шаблона в списке (описано ниже). Форма паттерна зависит от контекста, в котором происходит расширение.

Обратите внимание на ноль или больше. В вашем случае есть пустой пакет, поэтому экземпляры шаблона (print(args), 0)... равны нулю. Следовательно, вы не получите ошибку времени компиляции, потому что выражение:

auto x = {0, (print(args), 0)...};

фактически оценивается как:

auto x = {0};

то есть print никогда не вызывается в коде, сгенерированном компилятором.

person 101010    schedule 23.06.2016
comment
Я не думаю, что он оценивается как auto x = {0,0}; Я думаю, что он становится просто auto x = {0};, так как пакет параметров пуст DEMO ›› coliru.stacked-crooked.com/a/21723ed6d3b33b2e - person gedamial; 23.06.2016