Variadic template: candidate expects 1 argument, 0 provided (演绎错误)

Variadic template: candidate expects 1 argument, 0 provided (deduction error)

看看这段代码

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

int main()
{
     Variadic();
}

当我编译它时说:

candidate: template void print(T)

candidate expects 1 argument, 0 provided

他是对的。其实我在Parameter Pack里面并没有提供任何参数。

但是为什么这段代码可以编译?

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};

为什么编译器没有给我与以前完全相同的错误?

您误解了 ... 扩展运算符的工作原理。在您的示例中,当 args 是一个空包时,(print(args), 0)... 展开为空,而不是 print()

如果 args 作为 x 给出,它将扩展为 print(x), 0

如果 args 作为 x, y 给出,它将扩展为 (print(x), 0), (print(y), 0)

等等

基本上,它扩展了所有包含 args 的表达式并将其应用于,而不仅仅是 args 位本身。

来自标准[temp.variadic]:

  1. A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list. The form of the pattern depends on the context in which the expansion occurs.

...

  1. The instantiation of a pack expansion that is neither a sizeof... expression nor a fold-expression produces a list E1, E2, ..., EN , where N is the number of elements in the pack expansion parameters. Each Ei is generated by instantiating the pattern and replacing each pack expansion parameter with its ith element.

根据 C++ 标准 14.5.3/p4 可变参数模板 [temp.variadic]Emphasis Mine):

A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below). The form of the pattern depends on the context in which the expansion occurs.

注意零个或多个。在您的情况下,有一个空包,因此模式 (print(args), 0)... 的实例化为零。因此,您不会收到编译时错误,因为 expression:

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

实际计算为:

auto x = {0};

也就是说,print不会在编译器生成的代码中被调用。