请查看此代码段
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&lt;&gt;
好的,现在让我们继续:编译器看到
(print(args), 0)...
尝试调用print()...哦等等...... 参数包为空,print()函数为1参数。
为什么它会评估为auto x = {0};
呢?
为什么编译器没有给我与以前完全相同的错误?
答案 0 :(得分:5)
您误解了...
扩展运算符的工作原理。在您的示例中,当args
为空包时,(print(args), 0)...
会扩展为空,而不是print()
。
如果args
为x
,则会扩展为print(x), 0
。
如果args
为x, y
,则会扩展为(print(x), 0), (print(y), 0)
。
等
基本上它扩展了包含args
的所有表达式,并且它不仅应用于args
位本身。
来自标准[temp.variadic]:
- 包装扩展由图案和省略号组成 实例化产生零或更多的实例化 列表中的模式。模式的形式取决于上下文 发生了扩张。
醇>...
- 包扩展的实例化既不是sizeof ...表达式也不是fold-expression产生列表E1,E2,...,EN, 其中N是包扩展参数中的元素数。 每个Ei都是通过实例化模式并替换每个模式生成的 使用第i个元素打包扩展参数。
醇>
答案 1 :(得分:1)
根据C ++ 标准14.5.3 / p4 Variadic模板[temp.variadic] ( Emphasis Mine ):
包扩展包含模式和省略号, 实例化产生零或更多的实例化 列表中的模式(如下所述)。模式的形式取决于 关于扩张发生的背景。
注意零或更多。在你的情况下,有一个空包,因此模式(print(args), 0)...
的实例化为零。因此,您没有得到编译时错误,因为表达式:
auto x = {0, (print(args), 0)...};
实际评估为:
auto x = {0};
即,print
永远不会在编译器生成的代码中调用。