该标准提到f(a,(t=3,t+2),c); 根据我的理解,这将是一个赋值表达式,后跟第二个运算符的表达式。
但语法将其并列列出:
表达:
赋值表达式
表达式,赋值表达式
工作草案,编程语言标准 C ++ 修订版 N4140(2014 年 11 月)
有人这么好,可以向我解释一下我在这里缺少什么吗?
该标准提到f(a,(t=3,t+2),c); 根据我的理解,这将是一个赋值表达式,后跟第二个运算符的表达式。
但语法将其并列列出:
表达:
赋值表达式
表达式,赋值表达式
工作草案,编程语言标准 C ++ 修订版 N4140(2014 年 11 月)
有人这么好,可以向我解释一下我在这里缺少什么吗?
当你看到
expression: assignment-expression expression, assignment-expression
这意味着有两种表达的可能性。一种可能性,它只是assignment-expression
在前面的某个地方定义的。或者递归表示为expression, assignment-expression
因此,在扩展它之后,您会收到该表达式是一个或多个赋值表达式标记的逗号分隔列表。
在示例中,您提到第二个参数是表达式 (t=3,t+2),它由 2 个逗号分隔的赋值表达式组成 - 因为它出现“在逗号被赋予特殊含义的上下文中”它必须“仅出现在括号中”。
要找出为什么 assignment-expression 可以采用 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
请注意,由于表达式的定义是
表达式:
赋值表达式
表达式
,
赋值表达式
第二行意味着任何赋值表达式都可以被认为是一个表达式,这就是为什么t=3, t+2
它是一个有效的表达式。
那么为什么语法是这样的呢?首先请注意,表达式的语法是从最紧密绑定的类别primary-expression到最不紧密绑定的类别表达式逐步构建的。(
(然后“表达式 )
”是主表达式这一事实使表达式语法完整循环,并让我们通过添加括号使任何表达式比围绕它的所有内容更紧密地绑定。)
例如,众所周知的事实,即二进制*
比二进制更紧密的绑定+
来自以下语法片段:
乘法表达式:
pm-表达
乘法表达式
*
pm-表达式乘法表达式
/
pm-表达式乘法表达式
%
pm-表达式加法表达式:
乘法表达式
加法表达式
+
乘法表达式加法表达式
-
乘法表达式
在表达式2 + 3 * 4
中,文字2
,3
和4
可以被认为是pm-expression,因此也可以被认为是乘法表达式或加法表达式。所以你可能会说2 + 3
有资格作为一个加法表达式,但它不是一个乘法表达式,所以完全2 + 3 * 4
不能那样工作。相反,语法强制3 * 4
被视为乘法表达式,因此2 + 3 * 4
可以是加法表达式。因此3 * 4
是二进制的子表达式+
。
或者在 expression2 * 3 + 4
中,3 + 4
可能被认为是additive-expression,但它不是pm-expression,所以这不起作用。相反,解析器必须识别出它2 * 3
是一个乘法表达式,它也是一个加法表达式,因此2 * 3 + 4
也是一个有效的加法表达式,2 * 3
作为 binary 的子表达式+
。
当同一个运算符被使用两次或两个具有相同优先级的运算符被使用时,大多数语法定义的递归性质很重要。
回到逗号语法,如果我们有标记“ a, b, c
”,我们可能会说b, c
可能是一个表达式,但它不是一个赋值表达式,所以b, c
不能是整体的子表达式。相反,语法要求将其识别a, b
为一个表达式,它被允许作为另一个逗号运算符的左子表达式,因此也是a, b, c
一个作为左操作数的表达式。a, b
这对内置逗号没有任何区别,因为它的含义是关联的:“评估和丢弃a
,然后结果值来自评估(评估和丢弃b
,然后结果值来自评估c
)”与“评估和丢弃(评估和丢弃a
,然后结果值来自评估b
),然后结果值来自评估c
”。
但它确实为我们提供了在重载的情况下明确定义的行为operator,
。鉴于:
struct X {};
X operator,(X, X);
X a, b, c;
X d = (a, b, c);
我们知道最后一行意味着
X d = operator,(operator,(a,b), c);
并不是
X d = operator,(a, operator,(b,c));
(我认为定义一个 non-associative 是特别邪恶的operator,
,但它是允许的。)
这是语法符号(参见 N4140 的 §1.6)。
它主要用于评估优先级,但名称可能会产生误导。
例如在 [expr.ass] (§5.18) 你有以下定义:
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
assignment-operator: one of
= *= /= %= += -= >>= <<= &= ^= |=
所以 anassignment-expression
可以是 aconditional-expression
或 athrow-expression
即使两者都不执行任何赋值。
这只是说明a = b
, throw 10
orcond ? c : d
是具有相同优先顺序的表达式。
f(a,(t=3,t+2),c);
在这里,首先存储3
到t
变量中,然后f()
使用三个参数调用函数。这意味着第二个参数值成为5
并传递给函数。