2

看看这个代码片段

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

int main()
{
     Variadic();
}

当我编译它说:

候选:模板无效打印(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};

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

4

2 回答 2

5

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

如果args给出,x它将扩展到print(x), 0.

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

等等

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

从标准[temp.variadic]:

  1. 包扩展由一个模式和一个省略号组成,其实例化会在 list 中产生零个或多个模式的实例化。模式的形式取决于扩展发生的上下文。

...

  1. 既不是 sizeof... 表达式也不是折叠表达式的包扩展的实例化生成一个列表 E1, E2, ..., EN ,其中 N 是包扩展参数中的元素数。 每个 Ei 都是通过实例化模式并用其第 i 个元素替换每个包扩展参数来生成的
于 2016-06-23T15:40:14.330 回答
1

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

包扩展由一个模式和一个省略号组成,其实例化会在列表中产生零个或多个模式的实例化(如下所述)。模式的形式取决于扩展发生的上下文。

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

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

实际上评估为:

auto x = {0};

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

于 2016-06-23T15:49:56.350 回答