5.15 Logical OR operator in the standard says the following:
Unlike |, || guarantees left-to-right evaluation;
Does this mean somewhere I cannot locate in the standard, |
is defined to evaluate right-to-left, or that it is implementation-defined? Does this vary when the operator is overloaded? I wrote a quick program to test this and both MSVC++ and GCC seem to evaluate right-to-left.
#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;
}
This outputs 16
.
If ++a
and --b
are switched it outputs 19
.
I've also considered that I may be running into the multiple changes between sequence points rule (and thus undefined behavior), but I'm unsure how/if that applies with two separate instances as operands.
As others said, it means that the order of the evaluation of the two sides is unspecified. To answer your other questions -
I've also considered that I may be running into the multiple changes between sequence points rule (and thus undefined behavior)
No, your case does not modify foo
in between two adjacent sequence points. Before entering a function and before leaving a function, there always is a sequence point, which means that both modifications of foo
happen in between two different pairs of sequence points.
Does this vary when the operator is overloaded?
All of clause 5 only talks about builtin operators. For user defined operator implementations, the rules don't apply. So also for ||
, for user defined operators the order is not specified. But notice that it is only for user defined operators; not when both operands are converted to bool and trigger the builtin operator:
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()) ...;
}
This will always first execute A::operator bool
, and then B::operator bool
. And it will only call p->dosomething()
if p
evaluates to true
.