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

Posted

技术标签:

【中文标题】为啥编译器不能通过逗号运算符扩展可变参数模板的参数?【英文标题】:Why can't compilers expand arguments of a variadic template via comma operator?为什么编译器不能通过逗号运算符扩展可变参数模板的参数? 【发布时间】:2013-01-20 22:55:45 【问题描述】:

我知道we can't use variadic expansions as if it is a chain of comma operators。在那个问题中,样本是这样的:

template<typename... Args>
inline void increment_all(Args&... args) 

    ++args...; 

首先递增或扩展可能不明确,因此括号不会受到伤害:

template<typename... Args>
inline void increment_all(Args&... args)

    (++args)...; 

或类似的东西:

template<typename... Args>
void cout_all(Args&&... args)

    (std::cout << std::forward<Args>(args))...; 

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

【问题讨论】:

这是一个有趣的问题。我的怀疑是,要么他们不想处理它,要么考虑将包扩展到参数列表或根据上下文调用 , 运算符真的很难看,特别是如果你重载 @987654327 @运算符。 将您最喜欢的宠物功能添加到已经非常复杂的语言中的原因是什么?你得问问标准委员会。关键是可变参数模板的整个概念被添加到现有标准中,所以问为什么你可能有的任何给定的其他想法也没有被添加是有点没有实际意义。 感谢您提出这个问题。虽然我认为允许您建议的扩展是一个坏主意,但考虑到这一点帮助我为... 的工作方式提出了一个更好的心理模型。 【参考方案1】:

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

例如,f(args...) 扩展为函数参数列表,tuple&lt;Args...&gt; 扩展为模板参数列表。

在您的示例中,包扩展形成一个语句,语句的子表达式之间的逗号是逗号运算符,它可能被重载,导致任意复杂的代码,并且与内置逗号运算符不同,not 强制从左到右求值。如果您的 (std::cout &lt;&lt; std::forward&lt;Args&gt;(args))...; 示例以未指定的顺序写出 args,您会感到惊讶,因为参数包中的一种类型重载了 operator&lt;&lt;operator, 并破坏了评估顺序。

这样做不是对当前规则的简单扩展,而是完全不同的上下文,具有截然不同的效果。

首先递增或扩展可能不明确,因此括号不会受到伤害:

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

【讨论】:

+1 关键是,-运算符与逗号分隔函数和模板参数完全不同。最后,如果您可以使用, 扩展它们,为什么不使用+&lt;&lt;,它们都是运算符(尽管这将是一个不错的功能,我承认;))。也许扩展为单独的陈述,因此使用;,会更有意义(恕我直言,不会带来那么多问题)。但是好吧,递归模板爱好者也需要做点什么。 如果它会调用用户定义的逗号运算符重载会有什么问题?我想很多人都要求这个扩展,IMO C++ 肯定应该提供它。 (std::cout &lt;&lt; std::forward&lt;Args&gt;(args))... 永远不会以未指定的顺序写出 args - 它总是会生成相同的表达式。只是表达式的解释取决于上下文,但如果程序员也明确地编写逗号运算符元素,这将是正确的。

以上是关于为啥编译器不能通过逗号运算符扩展可变参数模板的参数?的主要内容,如果未能解决你的问题,请参考以下文章

可变参数模板包扩展

第21课 可变参数模板_展开参数包

为啥可变参数模板的模板特化与非可变模板的特化不同?

可变参数模板

为啥这个嵌套的可变参数模板是无效参数?

从可变参数模板中扩展的 decltype 继承