The code is following: (Coliru Code)
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <boost/logic/tribool.hpp>
struct B
{
boost::tribool boo;
void bug ()
{
bool tmp = indeterminate (boo);
std::cout << "tmp = " << std::boolalpha << tmp << "\n";
if (tmp && (boo = should_not_be_called ()) == false) {;}
}
bool should_not_be_called () const
{
std::cout << "BUG, wrong call\n";
abort ();
}
};
int main ()
{
B a;
a.bug ();
}
The output is
tmp = false
BUG, wrong call
bash: line 7: 14410 Aborted (core dumped) ./a.out
I cannot understand why should_not_be_called is called here. The tested compilers was gcc 4.9 and clang 3.6.
UPDATE:
I read the answers and changed the line with "if" to
if (tmp && (false == (boo = should_not_be_called ()))) {;}
(Coliru)
Now there are plain bool types on both sides of && operator, but I still got the same error. Why?
The compiler is in the right. Let's analyse the types involved in your two if
s, taking into account all the operator overloads that boost::tribool
provides:
if (tmp && (boo = should_not_be_called ()) == false) {;}
if (bool && (tribool = bool) == bool) {;} // = is overloaded to return tribool
if (bool && tribool == bool) {;} // == is overloaded to return tribool
if (bool && tribool) {;} // && is overloaded
And the second if
:
if (tmp && (false == (boo = should_not_be_called ()))) {;}
if (bool && (bool == (tribool = bool))) {;} // = is overloaded to return tribool
if (bool && (bool == tribool)) {;} // == is overloaded to return tribool
if (bool && tribool) {;} // && is overloaded
In both cases, we end up with an overloaded operator &&
. Operator overloads are functions which do not respect special calling behaviour of the built-in operators. That is, user-overloaded &&
, ||
do not short-circuit, and user overloads of ,
do not guarantee operand evaluation order. All three evaluate all of their operands, in unspecified order, just like any other function call.
This is precisely the reason why it is strongly discouraged to overload &&
, ||
, or ,
, if you want them to mean something like "and", "or" and "sequence."
Excerpt addressing original text of the question:
The compiler is in the right. boost::tribool
overloads opeator !
, which means the types of the operands of &&
are bool
and boost::tribool
. boost::tribool
also overloads operator &&
for these argument types, so this overload gets called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With