class my_bool {
private:
bool value;
public:
my_bool(bool value) : value(value) {}
explicit operator bool() { return value };
friend my_bool operator==(const my_bool & instance_1, const my_bool & instance_2);
friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2);
};
void main(){
my_bool a = true;
bool b = false;
if(a == b){
// do something
}
if(a && b){
// do something
}
}
I have just created a similar topic regarding my problem over here binary operator overloading; implicit type conversion . It can be deleted I guess because it is not explicit enough about the problem I am encountering.
Why is that operator== works fine and operator&& causes ambiguities? How do I solve this problem? I can surely write down two more overloads of operator&& (bool, my_bool), (my_bool, bool). That is a messy solution though
The builtin operator&& is a context in which expressions are contextually converted to bool. Other such contexts include for example the condition of if, for, while and the conditional operator ?.
Quoting N4296, §4/4 (the latest publicly available draft before C++14):
Certain language constructs require that an expression be converted to a Boolean value. An expression
eappearing in such a context is said to be contextually converted tobooland is well-formed if and only if the declarationbool t(e);is well-formed, for some invented temporary variablet(8.5).
Basically, this means that there is an "impicit explicit conversion to bool" in these contexts. Or, to illustrate this further, you can think of the following two lines being one and the same:
a && b
static_cast<bool>(a) && static_cast<bool>(b)
Therefore, the compiler must consider the explicit operator bool() when doing overload resolution for operator&&, but has to ignore it when doing overload resolution for operator== (since that operator does not force a "bool context" .. you can also compare numbers, strings, ...).
The solution in your case is IMO to get rid of the operator&&(const my_bool&, const my_bool&) all together. After all, it does not produce a more meaningful behavior than what would be possible by relying on the builtin operator&&(bool, bool). Establishing a second "boolean context" just isn't something the language was designed for (see below).
If you want to keep this operator, say for some side effects, then I see these choices:
Be explicit at the call site. That is:
if (static_cast<my_bool>(a) && static_cast<my_bool>(b)) { /* ... */ }
Be explicit at the definition site: Provide additional definitions for operator&&(my_bool const &, bool), operator&&(bool, my_bool const &). These then should rule out both operator&&(my_bool const &, my_bool const &) as well as operator&&(bool, bool) because the later are less specific. Adding these definitions to your class should mitigate the issue:
friend my_bool operator&&(const my_bool & lhs, bool rhs) {
// Delegate to operator&&(const my_bool &, const my_bool &)
return lhs && my_bool(rhs);
}
friend my_bool operator&&(bool lhs, const my_bool & rhs) {
// Delegate to operator&&(const my_bool &, const my_bool &)
return my_bool(lhs) && rhs;
}
Turns out one can "establish a boolean context", using CRTP:
#include <iostream>
using namespace std;
template<typename T>
struct bool_context {
friend T operator&&(T const & lhs, bool rhs) {
return lhs && T(rhs);
}
friend T operator&&(bool lhs, T const & rhs) {
return T(lhs) && rhs;
}
friend T operator||(T const & lhs, bool rhs) {
return lhs || T(rhs);
}
friend T operator||(bool lhs, T const & rhs) {
return T(lhs) || rhs;
}
};
struct my_bool : bool_context<my_bool> {
bool value;
my_bool(bool v) : value(v) {}
explicit operator bool() { return value; };
friend my_bool operator&&(my_bool const & lhs, my_bool const & rhs) {
cout << "my_bool::operator&&" << endl;
return lhs.value && rhs.value;
}
friend my_bool operator||(my_bool const & lhs, my_bool const & rhs) {
cout << "my_bool::operator||" << endl;
return lhs.value || rhs.value;
}
};
int main(int, char**) {
my_bool a = true;
bool b = false;
cout << "a && b => "; a && b; // my_bool::operator&&
cout << "b && a => "; b && a; // my_bool::operator&&
cout << "a && a => "; a && a; // my_bool::operator&&
cout << "b && b => "; b && b; cout << endl;
cout << "a || b => "; a || b; // my_bool::operator||
cout << "b || a => "; b || a; // my_bool::operator||
cout << "a || a => "; a || a; // my_bool::operator||
cout << "b || b => "; b || b; cout << endl;
return 0;
}
(Ideone)
My first thought on this is that the arguments to the compiler's built-in operator&& are (bool, bool), so my_bool's explicit bool operator can be invoked - since you are in effect, requesting an explicit conversion.
However, I can't find any reference in the standard as to whether a variable appearing on the right hand side of && should invoke an explicit conversion to bool.
Here's the complete error output from apple clang (once the source code above is fixed):
./nod.cpp:45:10: error: use of overloaded operator '&&' is ambiguous (with operand types 'my_bool' and 'bool')
if(a && b){
~ ^ ~
./nod.cpp:33:20: note: candidate function
friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2);
^
./nod.cpp:45:10: note: built-in candidate operator&&(_Bool, _Bool)
if(a && b){
^
1 error generated.
So how do I fix it?
Remove the user-defined && operator.
class my_bool {
private:
bool value;
public:
my_bool(bool value) : value(value) {}
explicit operator bool() { return value; }
friend my_bool operator==(const my_bool & instance_1, const my_bool & instance_2);
// friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2);
};
int main(){
my_bool a = true;
bool b = false;
if(a == b){
// do something
}
if(a && b){
// do something
}
}
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