问题
A quick search for C++ precedence yields many attempts. The disconcerting part is that they are all different. Most are assuredly wrong, albeit in minor details.
I will include three. The first, from cppreference.com claims there are 16 levels of precedence. Learn.cpp has 18. A simpler table at university of Purdue is much simpler.
http://en.cppreference.com/w/cpp/language/operator_precedence
http://www.learncpp.com/cpp-tutorial/31-precedence-and-associativity/
http://web.ics.purdue.edu/~cs240/misc/operators.html
None of these is definitive, but when I looked at the draft ISO standard, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf it did not even have a table, stating that you could figure it out from context.
My questions are 1) is there a good, definitive summary of precedence anywhere?
2) can anyone comment on all the differing "facts" conveyed by these tables?
For example, the first two agree that postincrement/decrement is on the same level as parentheses, what does that mean in practice?
(x+1)++
makes no sense because x+1 is an rexpr, and obviously parentheses which bracket an expression invalidate postincrement.
(*p)++;
I have read that postincrement is higher than preincrement, so I would put it just below () [] etc. What makes it equal (if it is)?
cppreference claims that throw is on the same level as assignment operators. This seems patently false, since:
throw x += 5;
should presumably first compute x += 5 before throwing. learncpp differs, and the third source doesn't mention throw as an operator at all.
This is the first time I have ever seen as an operator. I admit to not studying the standard for years, but return is a statement, why not throw?
Any comments illuminating bits of the precedence table would be great here.
回答1:
Precedence is not a part of the language specification. It is a mnemonic device used by us, humans, to understand the meaning of an expression without recursively analyzing it like an actual parser.
throw, ?: and all assignments in C++ are alternatives in the grammar production assignment-expression, defined as follows
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
Where conditional-expression is defined as logical-or-expression ? expression : assignment-expression, initializer-clause is another assignment-expression (when it isn't a braced-init-list), and throw-expression is defined as the keyword throw
followed by an optional assignment-expression
.
In human terms, we describe this as "same precedence, grouping right to left".
To reuse cppreference examples,
e = a < d ? a++ : a = d
parses as e = ((a < d) ? (a++) : (a = d))
and false ? 7 : throw 3
parses as false ? 7 : (throw 3)
, and yes, your example of throw x += 5
parses as throw (x += 5)
回答2:
Looking at your three sources, the order is essentially the same - C++ Reference groups throw and ?: together with assignment, which is separate in learncpp. Purdue's is much simpler, but also less specific.
Though it might look a bit complicated, I would recommend using learncpp's as a guideline, since it's the most specific. The parenthesis rule is a bit confusing; as a rule of thumb, use them as if they have highest precedence.
On the second part of your question...
(x+1)++;
certainly won't do anything, as (x+1) returns an r-value, which cannot be assigned to by the ++ operator.
(*p)++;
dereferences pointer p, and then increments the variable that it pointed to. Because dereferencing is lower than increment, without the parenthesis, it would dereference p and then increment the pointer, causing undefined behaviour.
I think the reason it's actually written such that postincrement is the same as () is that parenthesis would be done first anyways. Of course, if the () evaluates to an r-value, it will return an error. Preincrement is lower because if needed, the () has to go first. Take, for example,
++(*x);
In this case, x must be dereferenced first before incrementing it.
For your last question about throw, the tables list it as evaluated right-to-left. Your snippet of
throw x += 5;
will evaluate as
throw (x += 5);
It's listed as an operator because it's apparently an expression. Someone else with more knowledge on exception handling could probably explain this.
来源:https://stackoverflow.com/questions/30276755/c-precedence-definitive-list