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
e
appearing in such a context is said to be contextually converted tobool
and 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
}
}
The code bellow works in the same manner for both == and &&. The class equality is triggered only when are of the same type.
#include <stdio.h>
class my_bool {
private:
bool v{false};
public:
my_bool() : v(v) {};
operator bool (){return v;}
friend bool operator==(const my_bool a, my_bool b){
printf("operator==\n");return a.v==b;
}
friend bool operator&&(const my_bool a, my_bool b){
printf("operator&&\n");return a.v&&b;
}
};
int main(int argc, char **argv)
{ printf("Starting\n");
bool a=true,b=true;
my_bool A{},B{},R{};
a==b;a&&b;
a==A;a&&A;
A==b;A&&b;
A==B;A&&B;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.