5.15标准中的逻辑OR运算符表示如下:
与|,||不同保证从左到右的评估;
这是否意味着我无法在标准中找到,|
被定义为从右到左评估,或者它是实现定义的?当操作员超载时,这会有所不同吗?我写了一个快速程序来测试这个,MSVC ++和GCC似乎都在评估从右到左。
#include<iostream>
using namespace std;
int foo = 7;
class Bar {
public:
Bar& operator|(Bar& other) {
return *this;
}
Bar& operator++() {
foo += 2;
return *this;
}
Bar& operator--() {
foo *= 2;
return *this;
}
};
int main(int argc, char** argv) {
Bar a;
Bar b;
Bar c = ++a | --b;
cout << foo;
}
这会输出16
。
如果切换++a
和--b
,则会输出19
。
我还认为我可能会遇到序列点规则之间的多个变化(因此未定义的行为),但我不确定如何将两个单独的实例应用为操作数。
答案 0 :(得分:4)
暂时忽略该操作符,并注意这一点:
(x + y) * (z + 1)
这里,必须在乘法发生之前评估两个操作数(否则我们不知道要乘以什么)。在C ++中,完成此操作的顺序是未指定:首先可以是(x + y)
,或者首先是(z + 1)
,无论编译器感觉更好。†
运营商|
也是如此。但是,运算符||
必须短路,为了做到这一点,它必须严格从左到右进行评估。 (如果左侧评估结果为true
,则评估结束时不会评估正确的操作数。)这就是句子的含义。
†请注意,它可能没有这种或那种偏好,只是按照它列出的顺序进行评估。这就是你获得输出的原因,尽管你不能在语言层面上依赖它。
答案 1 :(得分:2)
这是否意味着我无法在标准中找到某个地方,|被定义为从右到左评估,还是由实现定义?
迂腐地说,|
运算符的参数的评估顺序是未指定的。这意味着可以按任何顺序评估操作数。
然而,从左到右指定了逻辑运算符(即&&
,||
等)和逗号运算符的操作数的评估顺序。
答案 2 :(得分:2)
正如其他人所说,这意味着双方的评估顺序没有具体说明。回答你的其他问题 -
我还认为我可能会遇到序列点规则之间的多重变化(因而未定义的行为)
不,您的案例不会修改两个相邻序列点之间的foo
。在进入函数之前和离开函数之前,始终存在序列点,这意味着foo
的两个修改都发生在两个不同的序列点对之间。
当操作员超载时,这会有所不同吗?
第5条的全部内容仅涉及内置运营商。对于用户定义的运算符实现,规则不适用。同样对于||
,对于用户定义的运算符,未指定顺序。但请注意,它仅适用于用户定义的运算符;不是当两个操作数都转换为bool并触发内置运算符时:
struct A {
operator bool() const { return false; }
};
struct B {
operator bool() const { return true; }
};
int main() {
A a;
B b;
a || b;
shared_ptr<myclass> p = ...;
if(p && p->dosomething()) ...;
}
这将始终首先执行A::operator bool
,然后B::operator bool
。如果p->dosomething()
评估为p
,则只会致电true
。