【问题标题】:Comma operator in C++11 (sequencing)C++11 中的逗号运算符(排序)
【发布时间】:2017-09-21 10:13:23
【问题描述】:

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

但语法将其并列列出:

表达式:

赋值表达式

表达式、赋值表达式

Working Draft, Standard for Programming Language C ++ Revision N4140 (November 2014)

有人好心向我解释一下我在这里缺少什么吗?

【问题讨论】:

  • 首先,assignment-expression 不能包含逗号(即在括号或引号之外)。因此,运算符左侧的assignment-expression 不能扩展到t=3 的右侧。其次,assignment-expression 是一个可能 包含赋值的,它不是必须的。因此,从技术上讲,运算符的每一侧都是一个 assignment-expression。这只是上下文无关语法的奇怪但非常有用的世界(请参阅en.wikipedia.org/wiki/Context-free_grammar)。这些规则的名称通常与您对自然语言的期望不符。

标签: c++ c++11 c++14 language-lawyer sequencing


【解决方案1】:

当你看到

 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

【讨论】:

    【解决方案2】:

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

    表达式

    赋值表达式

    表达式 , 赋值表达式

    第二行表示任何assignment-expression都可以被认为是一个表达式,这就是为什么t=3, t+2是一个有效的表达式。

    那么为什么语法是这样的呢?首先请注意,表达式的语法是从最紧密绑定的类别 primary-expression 到最不紧密绑定的类别 expression 逐步构建的。 (然后 "( expression )" 是一个 primary-expression 的事实使表达式语法完整循环,让我们使任何表达式更紧密通过添加括号来绑定而不是围绕它的所有内容。)

    例如,众所周知的事实是二进制 * 比二进制 + 绑定更紧密,这源于以下语法片段:

    乘法表达式

    pm-表达式

    乘法表达式 * pm-表达式

    乘法表达式 / pm-表达式

    乘法表达式 % pm-表达式

    加法表达式

    乘法表达式

    加法表达式 + 乘法表达式

    加法表达式 - 乘法表达式

    在表达式2 + 3 * 4 中,文字234 可以被认为是一个pm 表达式,因此也可以被认为是一个乘法表达式 或 additive-expression。所以你可能会说2 + 3 符合加法表达式的条件,但它不是乘法表达式,所以完整的@987654337 @ 不能那样工作。相反,语法强制3 * 4 被视为乘法表达式,因此2 + 3 * 4 可以是加法表达式。因此3 * 4 是二进制+ 的子表达式。

    或者在表达式2 * 3 + 4 中,3 + 4 可能被认为是一个additive-expression,但它不是一个pm-expression,所以这不是'不工作。相反,解析器必须认识到2 * 3 是一个乘法表达式,它也是一个加法表达式,所以2 * 3 + 4 是一个有效的加法表达式2 * 3 作为二进制 + 的子表达式。

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

    回到逗号语法,如果我们有标记“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));
    

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

    【讨论】:

    • 您写道:“第二行表示任何 assignment-expression 都可以被视为 expression,这就是为什么 t=3, t+2 是有效的表达。”为了证明这一点,你必须证明t+2 是一个assignment-expression。你能告诉我怎么做吗?
    • 在此上下文中,t标识符unqualified-idid-expression 和 主表达式。 2literalprimary-expression。每个 primary-expression 是一个 postfix-expressionunary-expressioncast-expressionpm -表达式乘法表达式t 也是一个 additive-expressiont+2 是一个 additive-expression, shift-expression, ..., 条件表达式和赋值表达式.
    • 谢谢。就我而言,你的答案是正确的。
    【解决方案3】:

    这是语法符号(参见 N4140 的 §1.6)。

    主要用于评估优先级,但名称可能会产生误导。

    例如,在 [expr.ass] (§5.18) 中,您有以下定义:

    assignment-expression:
       conditional-expression
       logical-or-expression assignment-operator initializer-clause
       throw-expression
    
    assignment-operator: one of
       = *= /= %= += -= >>= <<= &= ^= |=
    

    所以assignment-expression 可以是conditional-expressionthrow-expression,即使两者都不执行任何分配。

    这只是说明a = bthrow 10cond ? c : d 是具有相同优先顺序的表达式。

    【讨论】:

    • 这三个表达式的优先顺序不同。语法指定throw= 绑定更紧密,?: 左侧的=?: 更宽松,= 右侧的= 比@987654335 绑定更紧密@.
    【解决方案4】:
     f(a,(t=3,t+2),c);
    

    在这里,首先将3 存储到t 变量中,然后使用三个参数调用函数f()。这意味着第二个参数值变为5并传递给函数。

    【讨论】:

    • 是的,就是这样。但是它如何匹配语法 expression, assignment-expression 看起来赋值应该在 逗号之后?
    猜你喜欢
    • 2013-12-02
    • 1970-01-01
    • 2017-07-11
    • 2010-12-16
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    相关资源
    最近更新 更多