Reputation: 5569
I recently came across a code snippet that looked like this:
bool MyClass::do_work()
{
bool success = true;
for (auto const& worker : m_workers)
{
success &= worker.do_work(); // worker.do_work() returns a bool
}
return success;
}
If I understand it correctly, the function returns true
if all workers return true
and it returns false
if any worker returns false. However, it always evaluates all workers (which is desired). There is no short-circuit evaluation involved, since the bitwise operator &=
was used and not the logical operator &&
.
Is this behavior guaranteed? To be exact, is it guaranteed that bitwise &
always evaluates both operands, even if they are of type bool
? I came across many SO answers regarding guaranteed short-circuit evaluation for &&
, but none of them state that there is guaranteed non-short-circuit evaluation for &
.
If this behavior is guaranteed, is this a good programming style? It took me more than a quick glance to understand the function, because I have not seen this style before, and at first I was confused whether short-circuit evaluation was involved or not.
Is there a better alternative than the following?
bool MyClass::do_work()
{
bool success = true;
for (auto const& worker : m_workers)
{
if (!worker.do_work())
{
success = false;
}
}
return success;
}
Upvotes: 0
Views: 193
Reputation: 37606
Unless explicitly specified by the standard, all operands of an operator are evaluated and unsequenced1 in C++:
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. [...]
The only three exceptions that come to my mind are the &&
, ||
and ?:
operators2.
The standard even mentions for &&
3 that:
Unlike
&
,&&
guarantees left-to-right evaluation: the second operand is not evaluated if the first operand isfalse
.
As for if this is good programming style, this is opinion-based.
1 Unsequenced basically means that if you have A @ B
(where @
is an operator), B
(and its side effects) can be evaluated before A
, which is why construct such as i++ + ++i
are undefined behavior.
2 Note that for overloaded &&
and ||
operator, this is not true anymore since both operands are evaluated. ?:
cannot be overloaded.
3 There is a similar note for |
within [expr.log.or].
Upvotes: 4