C++ 11中的逗号运算符(排序)

Sta*_*owl 4 c++ language-lawyer sequencing c++11 c++14

标准提到f(a,(t = 3,t + 2),c); 根据我的理解,这将是赋值表达式,后跟第二个运算符的表达式.

但语法列出并列:

表达:

赋值表达式

表达式,赋值表达式

编程语言标准C++修订版N4140(2014年11月)

有人这么好,向我解释一下,我在这里错过了什么?

Art*_*sky 8

当你看到

 expression:
    assignment-expression
    expression, assignment-expression
Run Code Online (Sandbox Code Playgroud)

这意味着表达有两种可能性.它的一种可能性就是在assignment-expression某个地方提前定义的.或者以递归方式表示为expression, assignment-expression

因此,在扩展它之后,您会收到该表达式是一个或多个赋值表达式标记的逗号分隔列表.

在示例中,您提到的第二个参数是表达式(t = 3,t + 2),它由2个逗号分隔的赋值表达式组成 - 并且因为它出现"在逗号被赋予特殊含义的上下文中"它必须"只出现在括号中".

要找出为什么赋值表达式可以采用t + 2的形式,你必须从它的定义返回并始终选择第一选择

assignment-expression
-> conditional-expression
--> logical-or-expression
---> logical-and-expression
----> inclusive-or-expression
-----> exclusive-or-expression
------> and-expression
-------> equality-expression
--------> relational-expression
---------> shift-expression
----------> additive-expression - this is what you see
Run Code Online (Sandbox Code Playgroud)


asc*_*ler 5

请注意,由于表达式的定义是

\n
\n

表达

\n

\xe2\x80\x83赋值表达式

\n

\xe2\x80\x83表达式 , 赋值表达式

\n
\n

第二行意味着任何赋值表达式都可以被视为表达式,这就是为什么t=3, t+2是有效表达式。

\n

那么为什么语法是这样的呢?首先请注意,表达式的语法是按照从最紧密绑定类别Primary-Expression到最不紧密绑定类别expression的步骤构建的。( (然后,“表达式 )”是主要表达式这一事实使表达式语法完整地循环起来,并让我们通过添加括号使任何表达式比它周围的所有表达式都更紧密地绑定。)

\n

例如,众所周知的事实是二进制*比二进制绑定更紧密,+从这些语法片段可以得出结论:

\n
\n

乘法表达式

\n

\xe2\x80\x83 pm-表达式

\n

\xe2\x80\x83乘法表达式 * pm-表达式

\n

\xe2\x80\x83乘法表达式 / pm-表达式

\n

\xe2\x80\x83乘法表达式 % pm-表达式

\n

加法表达式

\n

\xe2\x80\x83乘法表达式

\n

\xe2\x80\x83加法表达式 + 乘法表达式

\n

\xe2\x80\x83加法表达式 - 乘法表达式

\n
\n

在表达式 中2 + 3 * 4,文字234可以被视为pm 表达式,因此也可以被视为乘法表达式加法表达式。所以你可能会说它2 + 3有资格作为一个加法表达式,但它不是一个乘法表达式,所以完整的2 + 3 * 4不能那样工作。相反,语法强制3 * 4被视为乘法表达式,因此2 + 3 * 4可以是加法表达式。因此3 * 4是二进制 的子表达式+

\n

或者在表达式中2 * 3 + 43 + 4可能被认为是附加表达式,但它不是pm-表达式,所以这是行不通的。相反,解析器必须识别出这2 * 3是一个乘法表达式,它也是一个加法表达式,因此2 * 3 + 4是一个有效的加法表达式2 * 3作为二进制的子表达式+

\n

当同一运算符使用两次或使用两个具有相同优先级的运算符时,大多数语法定义的递归性质很重要。

\n

回到逗号语法,如果我们有标记“ a, b, c”,我们可以说b, c可以是一个表达式,但它不是一个赋值表达式,因此b, c不能是整体的子表达式。相反,语法需要识别a, b表达式,它允许作为另一个逗号运算符的左子表达式,因此a, b, c也是作为左操作数的表达式。a, b

\n

这对于内置逗号没有任何区别,因为它的含义是关联的:“评估并丢弃a,然后结果值来自评估(评估并丢弃b,然后结果值来自评估c)”与“评估并丢弃(评估并丢弃a,则结果值来自评估b),则结果值来自评估c”。

\n

但它确实为我们提供了在重载的情况下明确定义的行为operator,。鉴于:

\n
struct X {};\nX operator,(X, X);\nX a, b, c;\nX d = (a, b, c);\n
Run Code Online (Sandbox Code Playgroud)\n

我们知道最后一行的意思是

\n
X d = operator,(operator,(a,b), c);\n
Run Code Online (Sandbox Code Playgroud)\n

并不是

\n
X d = operator,(a, operator,(b,c));\n
Run Code Online (Sandbox Code Playgroud)\n

(我认为定义非关联特别邪恶operator,,但这是允许的。)

\n