C++ Precedence definitive list [closed]

本小妞迷上赌 提交于 2019-12-10 10:47:04

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!