Disadvantages of the bitlevel operators.
You ask:
“Is there any reason not to use the bitwise operators &
, |
, and ^
for "bool" values in C++? ”
Yes, the logical operators, that is the built-in high level boolean operators !
, &&
and ||
, offer the following advantages:
Guaranteed conversion of arguments to bool
, i.e. to 0
and 1
ordinal value.
Guaranteed short circuit evaluation where expression evaluation stops as soon as the final result is known.
This can be interpreted as a tree-value logic, with True, False and Indeterminate.
Readable textual equivalents not
, and
and or
, even if I don't use them myself.
As reader Antimony notes in a comment also the bitlevel operators have alternative tokens, namely bitand
, bitor
, xor
and compl
, but in my opinion these are less readable than and
, or
and not
.
Simply put, each such advantage of the high level operators is a disadvantage of the bitlevel operators.
In particular, since the bitwise operators lack argument conversion to 0/1 you get e.g. 1 & 2
→ 0
, while 1 && 2
→ true
. Also ^
, bitwise exclusive or, can misbehave in this way. Regarded as boolean values 1 and 2 are the same, namely true
, but regarded as bitpatterns they're different.
How to express logical either/or in C++.
You then provide a bit of background for the question,
“I sometimes run into situations where I want exactly one of two conditions to be true (XOR), so I just throw the ^ operator into a conditional expression.”
Well, the bitwise operators have higher precedence than the logical operators. This means in particular that in a mixed expression such as
a && b ^ c
you get the perhaps unexpected result a && (b ^ c)
.
Instead write just
(a && b) != c
expressing more concisely what you mean.
For the multiple argument either/or there is no C++ operator that does the job. For example, if you write a ^ b ^ c
than that is not an expression that says “either a
, b
or c
is true“. Instead it says, “An odd number of a
, b
and c
are true“, which might be 1 of them or all 3…
To express the general either/or when a
, b
and c
are of type bool
, just write
(a + b + c) == 1
or, with non-bool
arguments, convert them to bool
:
(!!a + !!b + !!c) == 1
Using &=
to accumulate boolean results.
You further elaborate,
“I also need to accumulate Boolean values sometimes, and &=
and |=?
can be quite useful.”
Well, this corresponds to checking whether respectively all or any condition is satisfied, and de Morgan’s law tells you how to go from one to the other. I.e. you only need one of them. You could in principle use *=
as a &&=
-operator (for as good old George Boole discovered, logical AND can very easily be expressed as multiplication), but I think that that would perplex and perhaps mislead maintainers of the code.
Consider also:
struct Bool
{
bool value;
void operator&=( bool const v ) { value = value && v; }
operator bool() const { return value; }
};
#include <iostream>
int main()
{
using namespace std;
Bool a = {true};
a &= true || false;
a &= 1234;
cout << boolalpha << a << endl;
bool b = {true};
b &= true || false;
b &= 1234;
cout << boolalpha << b << endl;
}
Output with Visual C++ 11.0 and g++ 4.7.1:
true
false
The reason for the difference in results is that the bitlevel &=
does not provide a conversion to bool
of its right hand side argument.
So, which of these results do you desire for your use of &=
?
If the former, true
, then better define an operator (e.g. as above) or named function, or use an explicit conversion of the right hand side expression, or write the update in full.