折叠表达式的结合性
Associativity of fold-expressions
N4191 向 C++ 提出了折叠表达式。那里的定义是
(args + ...)
是左折(即 (((a0 + a1) + a2) + ...)
,
(... + args)
是右折叠(即(... + (a8 + (a9 + a10)))
。但是,修改后的论文N4295颠倒了左右一元折叠的定义。
问题:原理是什么?从左到右评估 (args + ...)
似乎更直观(至少当您习惯从左到右的字母表时)。
我不能代表提案,但新的、互换的定义对我来说似乎很自然。我的理由是 (... + args)
是左折叠的子表达式,而 (args + ...)
是右折叠的子表达式。事实上,前者是最后一段,后者是表达式的开始段(我可能使用的术语不正确)。
以下是我将如何从语法中说明折叠的扩展:
左折
(... + args)
(... + args) + a999)
(... + args) + a998) + a999)
((...((a0 + a1) + a2)...) + a999)
右折
(args + ...)
(a0 + (args + ...)
(a0 + (a1 + (args + ...)
(a0 + (...(a997 + (a998 + a999))...))
根据@cpplearner 的评论,这里有一些来自 std-discussion 的考古学
2015 年 2 月 4 日星期三上午 1:30,@T.C. wrote:
In N4295, which was actually voted into the standard,
(... op e)
is a unary left fold;
(e op ...)
is a unary right fold;
In N4191, however,
(e op ...)
is called a left fold.
(... op e)
is called a right fold.
Why the 180-degree turn?
@RichardSmith 的回答
The form in the original paper was simply a typo. Here are some
reasons why the definition that was voted into the standard is the
correct one:
In the standard's formulation, (e op ...)
has subexpressions of the form (e_i op <stuff>)
. It does not have subexpressions of the
form (<stuff> op e_i)
. This is consistent with all other pack
expansions, where the expansion comprises repeated instances of the
pattern.
(e op ... op eN)
, where eN
is a non-pack, must have eN
as the innermost operand in order to be useful -- that is, it must be
(e1 op (e2 op (e3 op (... op eN)...)))
, not (...(((e1 op e2) op e3)
op ...) op eN)
-- and vice versa for (e0 op ... op e)
. This allows,
for instance, (string() + ... + things)
and (std::cout << ... <<
things)
to work. For consistency, (e op ...)
must also be (e1 op
(e2 op (...)))
.
N4191 向 C++ 提出了折叠表达式。那里的定义是
(args + ...)
是左折(即 (((a0 + a1) + a2) + ...)
,
(... + args)
是右折叠(即(... + (a8 + (a9 + a10)))
。但是,修改后的论文N4295颠倒了左右一元折叠的定义。
问题:原理是什么?从左到右评估 (args + ...)
似乎更直观(至少当您习惯从左到右的字母表时)。
我不能代表提案,但新的、互换的定义对我来说似乎很自然。我的理由是 (... + args)
是左折叠的子表达式,而 (args + ...)
是右折叠的子表达式。事实上,前者是最后一段,后者是表达式的开始段(我可能使用的术语不正确)。
以下是我将如何从语法中说明折叠的扩展:
左折
(... + args)
(... + args) + a999)
(... + args) + a998) + a999)
((...((a0 + a1) + a2)...) + a999)
右折
(args + ...)
(a0 + (args + ...)
(a0 + (a1 + (args + ...)
(a0 + (...(a997 + (a998 + a999))...))
根据@cpplearner 的评论,这里有一些来自 std-discussion 的考古学
2015 年 2 月 4 日星期三上午 1:30,@T.C. wrote:
In N4295, which was actually voted into the standard,
(... op e)
is a unary left fold;
(e op ...)
is a unary right fold;In N4191, however,
(e op ...)
is called a left fold.
(... op e)
is called a right fold.Why the 180-degree turn?
@RichardSmith 的回答
The form in the original paper was simply a typo. Here are some reasons why the definition that was voted into the standard is the correct one:
In the standard's formulation,
(e op ...)
has subexpressions of the form(e_i op <stuff>)
. It does not have subexpressions of the form(<stuff> op e_i)
. This is consistent with all other pack expansions, where the expansion comprises repeated instances of the pattern.
(e op ... op eN)
, whereeN
is a non-pack, must haveeN
as the innermost operand in order to be useful -- that is, it must be(e1 op (e2 op (e3 op (... op eN)...)))
, not(...(((e1 op e2) op e3) op ...) op eN)
-- and vice versa for(e0 op ... op e)
. This allows, for instance,(string() + ... + things)
and(std::cout << ... << things)
to work. For consistency,(e op ...)
must also be(e1 op (e2 op (...)))
.