Reputation: 11251
I like to refactor complicated conditionals like this:
if (foo(blah) || (bar(param1, param2, param3) && !obj.longMethodName())) ...
into this:
bool foo_true = foo(blah);
bool bar_true = bar(param1, param2, param3);
bool long_true = obj.longMethodName();
if (foo_true || (bar_true && !long_true)) ...
I think this makes the code a lot easier to understand, and it helps with debugging because you can see the intermediate results used to compute the final condition.
But: in the original code, due to short circuiting, bar
will only be evaluated if foo
returns true
, and longMethodName
only if bar
returns true
.
Assume that functions are "pure", methods are const
, and the compiler can see the function bodies of everything. Are C++ optimizers allowed to defer evaluating my intermediate values until they are needed?
Upvotes: 1
Views: 152
Reputation: 153909
Of course. Provided the compiler can see enough to determine
that foo
, bar
and obj.longMethodName()
don't have any
other impact on the observable behavior of your code.
Whether any compilers do is another question. I rather doubt it; it would require some very special logic, which isn't in the usual list of optimization techniques, for something that practically nobody does. (I suspect that most programmers would find the original version, formatted correctly, to be more readable than the one with a lot of extra variables.)
I wonder if it's worth pointing out that the compiler is allowed to call all three functions even if the if is written:
if ( foo( blah ) || (bar( p1, p2, p3 ) && ! obj.lMN() ) )
(Although I can't imagine one that would.) The standard makes no requirements with regards to which functions are called when; it only requires that the observable behavior be the same (same values and in the same order---no guarantees with regards to time) "as if" the formal semantics of the program were followed. And the only things that count as observable behavior is IO (in some form) and accesses to volatile objects.
Upvotes: 4
Reputation: 16070
I am not sure if the assignment would be counted as a side-effect already. To say the least it is probably hard to determine if it is safe to move the actual call.
But, I would like to point out that in c++11 it is possible to achieve what OP pursues with nearly exact same syntax that OP uses in examples utilizing std::bind
.
It is just that foo_true
, would not be defined as
bool foo_true = foo(blah);
but rather
auto foo_true = std::bind(foo, blah)
.
The if
could be then checked as if( foo_true() || bar_true() )
.
Whether it is cleaner or not, is up to personal matter IMO. But I believe it behaves as both wanted, and expected. Full code:
#include <iostream>
#include <functional>
using namespace std;
bool foo(int blah){
cout << "blah: " << blah << '\n';
return blah;
}
bool bar(bool negate_me){
cout << "negate_me: " << negate_me << '\n';
return !negate_me;
}
int main() {
bool test = true;
int param = 42;
auto foo_true = std::bind(foo, test);
auto bar_true = std::bind(bar, param);
if (foo_true() || bar_true() ) cout << "TEST\n";
return 0;
}
Output:
blah: 1
TEST
bar
wasn't called. Change test
to false
and it will be.
Upvotes: 0
Reputation: 28872
The problem here is that foo
and bar
could be implemented in another compilation unit and C++ does not have the concept of function purity. This means that foo
and bar
might have side effects (changes to screen or global variables) and therefore must be evaluated in order for you to get expected behaviour.
Interestingly enough, with GCC, functions can be declared with the pure
attribute. This tells the compiler that the function does not have any side effects. And therefore can be called lazily. See here for more details.
Upvotes: 0
Reputation: 10064
No. C++ has no concept of a pure method with no side effects, so there really isn't a way to optimize that.
Upvotes: 0
Reputation: 22542
No. You compiler is not allowed to make the optimisation because it can not determine wether you have meant the short circuit or wether you want to have a potential side effect of evaluating bar
no matter what.
Upvotes: 1