N4191向 C++ 提出了折叠表达式。那里的定义是
(args + ...)
是一个左折叠(即(((a0 + a1) + a2) + ...)
,并且
(... + args)
是右折叠(即(... + (a8 + (a9 + a10)))
。但是,修订后的论文N4295颠倒了左右一元折叠的定义。
问题:原理是什么?从左到右进行评估似乎更直观(至少当您习惯于从左到右的字母表时)(args + ...)
。
从@cpplearner 的评论中,这是来自 std-discussion 的一些考古学
2015 年 2 月 4 日星期三凌晨 1:30,@TC 写道:
在实际上被投票纳入标准的 N4295 中,
(... op e)
是一元左折叠;
(e op ...)
是一元右折叠;然而,在 N4191 中,
(e op ...)
称为左折叠。
(... op e)
称为右折叠。为什么要180度大转弯?
@RichardSmith 的回答
原始论文中的表格只是一个错字。以下是投票纳入标准的定义正确的一些原因:
在标准的制定中,
(e op ...)
具有形式的子表达式(e_i op <stuff>)
。它没有形式的子表达式(<stuff> op e_i)
。这与所有其他包扩展一致,其中扩展包含模式的重复实例。
(e op ... op eN)
,其中eN
是非包,必须具有eN
作为最里面的操作数才能有用 - 也就是说,它必须是(e1 op (e2 op (e3 op (... op eN)...)))
,而不是(...(((e1 op e2) op e3) op ...) op eN)
- 反之亦然(e0 op ... op e)
。例如,这允许(string() + ... + things)
和(std::cout << ... << things)
工作。为了一致性,(e op ...)
还必须是(e1 op (e2 op (...)))
.
我不能代表提案,但新的、交换的定义对我来说似乎很自然。我的理由是这(... + args)
是左折叠(args + ...)
的子表达式,也是右折叠的子表达式。事实上,前者是最后一段,后者是表达式的初始段(我可能没有使用正确的术语)。
以下是我将如何从语法中说明折叠的扩展:
左折叠
(... + args)
(... + args) + a999)
(... + args) + a998) + a999)
((...((a0 + a1) + a2)...) + a999)
右折叠
(args + ...)
(a0 + (args + ...)
(a0 + (a1 + (args + ...)
(a0 + (...(a997 + (a998 + a999))...))