问题
The standard mentions f(a,(t=3,t+2),c); which would be an assignment-expression followed by an expression for the 2nd operator according to my understanding.
But the grammar lists it juxtaposed:
expression:
assignment-expression
expression, assignment-expression
Working Draft, Standard for Programming Language C ++ Revision N4140 (November 2014)
Is someone so nice as to explain to me please what it is that I'm missing here?
回答1:
When you see
expression: assignment-expression expression, assignment-expression
It mean that there are 2 possibilities for expression. One possibility that it is just assignment-expression
that is defined somewhere earlier. Or it is recursively represented as expression, assignment-expression
So after extending it you receive that expression is comma separated list of one or more assignment-expression tokens.
In the sample you're mentioned second parameter is expression (t=3,t+2) which consists of 2 comma-separated assignment-expressions - and since it appears "In contexts where comma is given a special meaning" it has to "appear only in parentheses".
To find out why assignment-expression could take a form of t+2 you have to go back from its definitions and choose first choice always
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:
This is the syntax notation (see §1.6 of N4140).
It is mainly used to evaluate precedence, but the name can be misleading.
For example in [expr.ass] (§5.18) you have the folowing definition:
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
assignment-operator: one of
= *= /= %= += -= >>= <<= &= ^= |=
So an assignment-expression
can be a conditional-expression
or a throw-expression
even if neither performs any assignment.
This just states that a = b
, throw 10
or cond ? c : d
are expressions with the same precedence order.
回答3:
Note that since the definition of expression is
expression:
assignment-expression
expression
,
assignment-expression
the second line means that any assignment-expression can be considered an expression, which is why t=3, t+2
is a valid expression.
So why is the grammar this way? First note that the grammar for expressions builds its way in steps from the most tightly bound category primary-expression to the least tightly bound category expression. (And then the fact that "(
expression )
" is a primary-expression brings the expression grammar full circle and lets us cause any expression to be more tightly bound than everything that surrounds it by adding parentheses.)
For example, the well-known fact that binary *
binds tighter than binary +
follows from these grammar pieces:
multiplicative-expression:
pm-expression
multiplicative-expression
*
pm-expressionmultiplicative-expression
/
pm-expressionmultiplicative-expression
%
pm-expressionadditive-expression:
multiplicative-expression
additive-expression
+
multiplicative-expressionadditive-expression
-
multiplicative-expression
In the expression 2 + 3 * 4
, the literals 2
, 3
, and 4
can be considered a pm-expression, or therefore also a multiplicative-expression or additive-expression. So you might say 2 + 3
would qualify as an additive-expression, but it is not a multiplicative-expression, so the full 2 + 3 * 4
can't work that way. Instead the grammar forces 3 * 4
to be considered a multiplicative-expression, so that 2 + 3 * 4
can be an additive-expression. Therefore 3 * 4
is a subexpression of the binary +
.
Or in the expression 2 * 3 + 4
, 3 + 4
might be considered an additive-expression, but then it is not a pm-expression, so that doesn't work. Instead the parser must recognize that 2 * 3
is a multiplicative-expression, which is also an additive-expression, so 2 * 3 + 4
is a valid additive-expression, with 2 * 3
as a subexpression of the binary +
.
The recursive nature of most grammar definitions matters when the same operator is used twice, or two operators with the same precedence are used.
Going back to the comma grammar, if we have the tokens "a, b, c
", we might say b, c
could be an expression, but it is not an assignment-expression, so b, c
cannot be a subexpression of the whole. Instead the grammar requires recognizing a, b
as an expression, which is allowed as a left subexpression of another comma operator, so a, b, c
is also an expression with a, b
as the left operand.
This doesn't make any difference for the built-in comma, since its meaning is associative: "evaluate and discard a
, then the result value comes from evaluating (evaluate and discard b
, then the result value comes from evaluating c
)" does the same as "evaluate and discard (evaluate and discard a
, then the result value comes from evaluating b
), then the result value comes from evaluating c
".
But it does give us a clearly-defined behavior in case of an overloaded operator,
. Given:
struct X {};
X operator,(X, X);
X a, b, c;
X d = (a, b, c);
we know that the last line means
X d = operator,(operator,(a,b), c);
and not
X d = operator,(a, operator,(b,c));
(I'd consider it particularly evil to define a non-associative operator,
, but it is allowed.)
回答4:
f(a,(t=3,t+2),c);
Here, first, stores 3
into t
variable, then calls function f()
with three arguments. It means second argument value become 5
and pass to the function.
来源:https://stackoverflow.com/questions/46341225/comma-operator-in-c11-sequencing