为什么编译器不能通过逗号运算符扩展可变参数模板的参数?

zah*_*hir 5 c++ comma variadic-templates c++11

我知道我们不能使用可变扩展,就好像它是一个逗号运算符链.在那个问题中,样本是这样的:

template<typename... Args>
inline void increment_all(Args&... args) 
{
    ++args...; 
}
Run Code Online (Sandbox Code Playgroud)

首先增加或扩展可能是不明确的,所以括号不会受到伤害:

template<typename... Args>
inline void increment_all(Args&... args)
{
    (++args)...; 
}
Run Code Online (Sandbox Code Playgroud)

或类似的东西:

template<typename... Args>
void cout_all(Args&&... args)
{
    (std::cout << std::forward<Args>(args))...; 
}
Run Code Online (Sandbox Code Playgroud)

我知道我们可以使用一些递归技巧来获得我们想要的东西,比如这样.我不知道为什么标准没有描述这种行为?我的意思是,背后的原因是什么?

Jon*_*ely 5

允许包扩展的其他上下文是列表,其中逗号是列表元素之间的分隔符,而不是运算符.

例如,f(args...)展开到函数参数列表,tuple<Args...>展开到模板参数列表.

在您的示例中,包扩展形成一个语句,语句的子表达式之间的逗号是逗号运算符,可能会重载,导致任意复杂的代码,与内置逗号运算符不同,强制从左到右的求值.你会惊讶,如果你的(std::cout << std::forward<Args>(args))...; 例子在指定顺序写出来的ARGS因为在参数包的类型之一超载operator<<operator,摔碎评价的顺序.

这样做不会是对当前规则的简单扩展,它将是一个完全不同的上下文,具有非常不同的效果.

首先增加或扩展可能是不明确的,所以括号不会受到伤害:

不,它不会含糊不清.它可以使用f(++args...),而且清晰明确.您的建议的难点不在于如何解析++args...它在将其扩展为包含逗号运算符的语句后会发生什么.