C++ 递增后运算符和递增前运算符的优先级
代码如下:C++ 递增后运算符和递增前运算符的优先级,c++,operators,C++,Operators,代码如下: #include <iostream> class Int { public: Int() : x(0) {} Int(int x_) : x(x_) {} Int& operator=(const Int& b) { std::cout << "= from " << x << " = " << b.x << std::endl; x =
#include <iostream>
class Int {
public:
Int() : x(0) {}
Int(int x_) : x(x_) {}
Int& operator=(const Int& b) {
std::cout << "= from " << x << " = " << b.x << std::endl;
x = b.x;
}
Int& operator+=(const Int& b) {
std::cout << "+= from " << x << " + " << b.x << std::endl;
x += b.x;
return *this;
}
Int& operator++() {
std::cout << "++ prefix " << x << std::endl;
++x;
return *this;
}
Int operator++(int) {
std::cout << "++ postfix " << x << std::endl;
Int result(*this);
++x;
return result;
}
private:
int x;
};
Int operator+(const Int& a, const Int& b) {
std::cout << "operator+" << std::endl;
Int result(a);
result += b;
return result;
}
int main() {
Int a(2), b(3), c(4), d;
d = ++a + b++ + ++c;
return 0;
}
虽然后缀运算符的优先级高于前缀运算符,但为什么后缀运算符不在前缀运算符(++前缀4)之前执行
这是由g++编译的。不同操作数的求值顺序未指定,这意味着编译器可以随意重新排序
++a
、b++
和++c
子表达式的求值顺序。在该示例中,运算符的优先级实际上没有任何影响
如果您尝试编写
++i++
(其中i
是int
),它将被分组为++(i++)
,并且它将无法编译,因为子表达式i++
是右值,前缀增量需要左值。如果优先级颠倒,则该表达式将编译(并导致未定义的行为)后缀++
在表达式+++a+b+++++c
中具有最高的优先级,但++
具有最低的优先级,并且是左关联的。这个表达式可以等价地写为(++a)+(b++++++++(++c)
(每个++
都是不同子表达式的一部分),这解释了为什么首先计算++a
。考虑遍历/评估相应的解析树,评估结果的顺序变得明显:
E
/ | \
/ | E
/ | | \
E + ++ c
/ | \
/ | \
E + E
/ \ / \
++ a b ++
它不会对
++a
、b++
和++c
进行重新排序,但它们的评估是独立的。我已经编译了这样的语句++a++(++b)++,没有错误。对于示例中的类,它可以工作,但对于像int这样的类型,它不能工作:error:levalue需要作为增量operand@Benoit:是的,我是从这个句子开始的,但后来忘了把最重要的地方说清楚。@scdmb:是的,我应该说得更准确些。在这种情况下,因为它是一种用户定义的类型,提供了表达式编译和良好定义的操作,但在基本类型为int
的情况下,注释为:int i=0++i++代码>编译失败,int i=0;(++i)+代码>是未定义的行为。对于用户定义的类型,++i++
将导致调用后增量,然后调用前增量,证明运算符的优先级,对吗?@scdmb:对于int i
,它是未定义的行为,因为(用C++03的说法)整数在表达式中修改两次,没有任何中间序列点。我必须回顾一下C++11标准,因为整个序列点术语都不存在了。。。至于一个可能出错的例子。。。在这个特定的例子中,很难找到可能导致不同结果的操作顺序,但标准允许这样做。
E
/ | \
/ | E
/ | | \
E + ++ c
/ | \
/ | \
E + E
/ \ / \
++ a b ++