问题
cppreference says:
the behavior of every builtin compound-assignment expression
E1 op= E2
(whereE1
is a modifiable lvalue expression andE2
is an rvalue expression or a braced-init-list (since C++11)) is exactly the same as the behavior of the expressionE1 = E1 op E2
, except that the expressionE1
is evaluated only once and that it behaves as a single operation with respect to indeterminately-sequenced function calls (e.g. inf(a += b, g())
, the+=
is either not started at all or is completed as seen from insideg()
)."
I want to know if this explanation is wrong (insufficient) or I'm understanding something incorrectly.
I understand there's inherent difference between E1 = E1 + E2
and E1 += E2
,
which is explained here:
#include<iostream>
int main() {
int x;
x = 1;
x += (-1) ? 2 : 2;
std::cout << x << std::endl; //prints 3
x = 1;
x = x + (-1) ? 2 : 2;
std::cout << x << std::endl; //prints 2
x = 2;
x += (-2) == 0;
std::cout << x << std::endl; //prints 2
x = 2;
x = x + (-2) == 0; // prints 1
}
My guess is E1 op= E2
has the following behavior:
- Evaluate
E1
andE2
(unsure about the order) and assign result of operation between two evaluation toE1
, which is(E1) = (E1) op (E2)
.
So would a better explanation for compound assignment operation's behavior be
(E1) = (E1) op (E2)
? (or E1 = E1 op (E2)
, because E1
only can have operator of higher precedence than assignment operator and lower precedence than op operator, without parentheses, if E1 op (E2)
wants to produce different result from (E1) op (E2)
. Such operator whose result is a modifiable lvalue doesn't exist.)
回答1:
That quote from cppreference comes directly from the C++ Standard:
[expr.ass]/6
The behavior of an expression of the form
E1 op= E2
is equivalent toE1 = E1 op E2
except thatE1
is evaluated only once.
Such expressions are deprecated ifE1
has volatile-qualified type; see[depr.volatile.type]
.
For+=
and-=
,E1
shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type.
In all other cases,E1
shall have arithmetic type.
In this context, the term expression has already been defined and E1 op= E2
being equivalent to E1 = E1 op E2
clearly doesn't mean the expressions are equivalent in their textual representation, but in their resolution (type, value and side-effects).
[A] better explanation for compound assignment operation's behavior could be (E1) = (E1) op (E2)?
I only can express my opinion: I think the cpprederence page is right to quote the Standard here, but a note could be added to make sure readers do not get it wrong.
回答2:
This is about operator precedence. +
has higher precedence than the ternary conditional (and also ==
). So this:
x = x + (-1) ? 2 : 2;
Is evaluated like this:
x = (x + (-1)) ? 2 : 2;
That's why you get 2
instead of 3
. Same with the other sample:
x = x + (-2) == 0
is evaluated as
x = (x + (-2)) == 0 // (x + (-2)) is 0, 0 == 0 is 1
So taking the first example:
x = x + (-1) ? 2 : 2;
Here A
is x
and B
is (x + (-1) ? 2 : 2)
(x
plus the result of the ternary operation)
Here, however
x += (-1) ? 2 : 2;
A
is x
and B
is just the result of the ternary operation. What A
and B
are changed due to +=
having a lower precedence than =
. So the statement about E1 = E1 + E2 and E1 += E2 being the same is correct, but it doesn't mean that transforming E1 = E1 + E2
to E1 += E2
will never change what E1
and E2
mean. Which seems a bit misleading.
回答3:
According to the C++ Standard (8.5.18 Assignment and compound assignment operators)
7 The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once. In += and -=, E1 shall either have arithmetic type or be a pointer to a possibly cv-qualified completely-defined object type. In all other cases, E1 shall have arithmetic type.
And (8.5.6 Additive operators)
1 The additive operators + and - group left-to-right. The usual arithmetic conversions (8.3) are performed for operands of arithmetic or enumeration type.
These expression statements
x = x + (-1) ? 2 : 2;
x += (-2) == 0;
x = x + (-2) == 0;
are equivalent to
x = ( x - 1 ) ? 2 : 2;
x += ( -2 == 0 );
x = ( ( x - 2 ) == 0 );
来源:https://stackoverflow.com/questions/57727204/compound-assignment-e1-op-e2-is-not-equivalent-to-e1-e1-op-e2