Context:
I have a class with an internal boolean value that seems like a good candidate for overloading operator bool, like this:
class MyBool{
private:
bool value_ = false;
// Nice API and logic to set the interal value_ to true or false...
public:
explicit operator bool() const {
return value_;
};
};
From https://en.cppreference.com/w/cpp/language/implicit_conversion, "Contextual conversions" section, this works in:
the controlling expression of if, while, for;
the operands of the built-in logical operators !, && and ||;
the first operand of the conditional operator ?:;
the predicate in a static_assert declaration;
the expression in a noexcept specifier;
Which explains why I get errors when trying to use it in other ways, like this:
MyBool x;
///...
bool y = x; // --> error: cannot convert ‘MyBool’ to ‘bool’ in initialization
// or:
bool z;
z = x; // --> error: cannot convert ‘MyBool’ to ‘bool’ in assignment
// Or returning from a function:
bool func(...){
MyBool x;
// ...
return x; // --> error: cannot convert ‘MyBool’ to ‘bool’ in return
}
// Or in Gtests, like:
MyBool x;
// ...
EXPECT_TRUE(x); // --> error: no matching function for call to ‘testing::AssertionResult::AssertionResult(MyBool)’
If I removed the explicit keyword, some problems cold arise because of implicit conversions (safe bool idiom in pre C++11: http://blog.asymptotic.co.uk/2014/03/the-safe-bool-idiom-in-c/).
In these cases, I could explicitly cast the MyBool variable to bool and it would work, but to me, this non-homogeneous use kind of defeats the purpose of overloading the operator, that is: to be able to naturally use MyBool as a bool. Instead, I could add a member function like this:
bool get_value() const {
return value_;
}
And use x.get_value() every time I need to "cast" to bool, even in the conditions, loops, etc.
The question is: is there a way to use this class in the cases above, or some of them, with modifications to the class code only (not the calling code), and without removing the explicit keyword?
(Preferrably in C++11).
The question seems to be how to both (1) have implicit conversion to bool and (2) avoid integer promotion/conversion. Delete the conversion to int:
class MyBool
{
public:
operator bool() const
{
return value_;
};
operator int() const = delete;
private:
bool value_ = false;
};
All of the lines in the question now compile because implicit conversion is allowed. And none of the safe-bool problems compile because integer conversion is deleted:
MyBool x;
int i = x;
x << 1;
x < 1;
C++20 version of deleting all the conversion operators that would in turn implicitly convert to bool:
#include <concepts>
class MyBool
{
private:
bool value_ = false;
public:
explicit operator bool() const { return value_; };
template <std::convertible_to<bool> T>
operator T() = delete;
};
Related
Given a simple class template with multiple implicit conversion functions (non-explicit constructor and conversion operator), as in the following example:
template<class T>
class Foo
{
private:
T m_value;
public:
Foo();
Foo(const T& value):
m_value(value)
{
}
operator T() const {
return m_value;
}
bool operator==(const Foo<T>& other) const {
return m_value == other.m_value;
}
};
struct Bar
{
bool m;
bool operator==(const Bar& other) const {
return false;
}
};
int main(int argc, char *argv[])
{
Foo<bool> a (true);
bool b = false;
if(a == b) {
// This is ambiguous
}
Foo<int> c (1);
int d = 2;
if(c == d) {
// This is ambiguous
}
Foo<Bar> e (Bar{true});
Bar f = {false};
if(e == f) {
// This is not ambiguous. Why?
}
}
The comparison operators involving primitive types (bool, int) are ambiguous, as expected - the compiler does not know whether it should use the conversion operator to convert the left-hand template class instance to a primitive type or use the conversion constructor to convert the right-hand primitive type to the expected class template instance.
However, the last comparison, involving a simple struct, is not ambiguous. Why? Which conversion function will be used?
Tested with compiler msvc 15.9.7.
According to [over.binary]/1
Thus, for any binary operator #, x#y can be interpreted
as either x.operator#(y) or operator#(x,y).
According to this rule, in the case of e == f, the compiler can only interpret it as e.operator==(f), not as f.operator==(e). So there is no ambiguity; the operator== you defined as a member of Bar is simply not a candidate for overload resolution.
In the case of a == b and c == d, the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T>.
Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called.
It always helps to write out the explicit call of an operator overload to better understand exactly what it does:
Foo<Bar> e (Bar{true});
Bar f = {false};
// Pretty explicit: call the member function Foo<Bar>::operator==
if(e.operator ==(f)) { /* ... */ }
This can't be confused with the comparison operator in Bar, because it would require an implicit conversion of the left-hand side, which is impossible.
You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this:
struct Bar { bool m; };
// A free function allows conversion, this will be ambiguous:
bool operator==(const Bar&, const Bar&)
{
return false;
}
This is nicely demonstrated and explained in Scott Meyers's Effective C++, Item 24.
In the class below,
Why would you make the operators explicit. I thought that explicit was to prevent implicit calling of constructors?
class Content
{
public:
virtual ~Content() = 0;
virtual explicit operator float&();
virtual explicit operator long long&();
virtual explicit operator std::string&()
}
I thought that explicit was to prevent implicit calling of
constructors?
Since C++11 it also applies to user-defined conversions (a.k.a. the cast operator).
Why would you make the operators explicit
Used in this context, the explicit keyword makes the conversion eligible only for direct-initialization and explicit conversions. See here under [class.conv.fct¶2]:
A conversion function may be explicit ([dcl.fct.spec]), in which case
it is only considered as a user-defined conversion for
direct-initialization ([dcl.init]). Otherwise, user-defined
conversions are not restricted to use in assignments and
initializations.
This aids you in making sure the compiler doesn't try the conversion against your intention, so that you have to explicitly cast it yourself, leaving less room for error. Example:
struct Foo
{
explicit operator int() {return 0;}
operator int*() {return nullptr;}
};
int main()
{
Foo foo;
//int xi = foo; // Error, conversion must be explicit
int i = static_cast<int>(foo); // OK, conversion is explicit
int* i_ptr = foo; // OK, implicit conversion to `int*` is allowed
int i_direct(foo); // OK, direct initialization allowed
int* i_ptr_direct(foo); // OK, direct initialization after implicit conversion
return 0;
}
It can also help resolve ambiguity in cases where multiple conversion options apply, leaving the compiler without a criteria for deciding which one to choose:
struct Bar
{
operator int() {return 1;}
operator char() {return '1';}
};
int main()
{
Bar bar;
//double d = bar; // Error, implicit conversion is ambiguous
return 0;
}
Add explicit:
struct Bar
{
operator int() {return 1;}
explicit operator char() {return '1';}
};
int main()
{
Bar bar;
double d = bar; // OK, implicit conversion to `int` is the only option
return 0;
}
Consider the following:
struct Content
{
operator float() { return 42.f; }
friend Content operator+(Content& lhs, float) { return lhs; }
};
int main()
{
Content c{};
c + 0; // error: ambiguous overload for 'operator+'
}
Here, the compiler cannot choose between operator+(Content&, float) and operator+(float, int). Making the float operator explicit resolves this ambiguity*:
c + 0; // operator+(Content&, float)
or
static_cast<float>(c) + 0; // operator+(float, int)
*) provided it makes sense to prefer one over the other.
The other answers cover how it works, but I think you should be told why it was added to C++.
A smart pointer usually has a conversion to bool so you can do this:
std::shared_ptr<int> foo;
if (foo) {
*foo = 7;
}
where if(foo) converts foo to bool. Unfortunately:
int x = foo+2;
converts foo to bool, then to int, then adds 2. This is almost always a bug. This is permitted because while only one user defined conversion is done, a user defined conversion followed by a built in conversion can silently occur.
To fix this programmers would do crazy things like add:
struct secret {
void unused();
};
struct smart_ptr {
using secret_mem_ptr = void(secret::*)();
operator secret_mem_ptr() const { return 0; }
};
and secret_mem_ptr is a secret pointer to member. A pointer to member has a built in conversion to bool, so:
smart_ptr ptr;
if (!ptr) {
}
"works" -- ptr is convert to secret_mem_ptr, which then is convered to bool, which is then used to decide which branch to take.
This was more than a bit of a hack.
They added explicit on conversion operators to solve this exact problem.
Now:
struct smart_ptr {
explicit operator bool() const { return true; }
};
doesn't permit:
smart_ptr ptr;
int x = 3 + ptr;
but it does permit:
if (ptr) {
}
because the rules were hand-crafted to support exactly that use case. It also doesn't permit:
bool test() {
smart_ptr ptr;
return ptr;
}
here, you have to type:
bool test() {
smart_ptr ptr;
return (bool)ptr;
}
where you explicitly convert ptr to bool.
(I am usually really against C-style casts; I make an exception in the case of (bool)).
You would use it if you wanted a Content object never to be implicitly converted to (say) a float. This could happen in the following way:
void f( float f );
....
Content c;
f( c ); // conversion from Content to float
Without the explicit qualifier, the conversion happens implicitly; with it, you get a compilation error.
Silent, implicit conversions can be the source of a lot of confusion and/or bugs, so it's generally better to make the operators explicit , or probably better yet to provide named functions, such as ToFloat, which tell the reader exactly what is going on.
I have a following example (with overly safe boolean type):
#include <cstdlib>
struct boolean_type
{
explicit
boolean_type(bool _value)
: value_(_value)
{ ; }
explicit
operator bool () const
{
return value_;
}
private :
bool value_;
};
struct A
{
A(int const _i)
: i_(_i)
{ ; }
boolean_type operator == (A const & _other) const
{
return (i_ == _other.i_);
}
private :
int i_;
};
bool t()
{
return A(0) == A(0);
}
int main()
{
return EXIT_SUCCESS;
}
It is well-known that such code containing an errors: "could not convert '(((int)((const A*)this)->A::i_) == ((int)other.A::i))' from 'bool' to 'boolean_type'" in return statement of bool A::operator == (A const &) const and "cannot convert 'boolean_type' to 'bool'" in return statement of bool t(). But what the risk here? Why there are not explicit conversion here in both cases? Why are implicit? In fact we explicitly specify the returning type bool in second case and static_assert(std::is_same< bool, decltype(std::declval< int >() == std::declval< int >()) >::value, "!"); as such!
Additionally want to say:
Due to the specified obstruction I cannot simply replace all entries of the bool to my super-safe boolean_type (which is mocked-object) in my user code, because, say, in return statement of boost::variant::operator == uses above construction, that treats there as implicit conversion. Similar obstructions are not unique.
You have two implicit conversions. One here:
return (i_ == _other.i_);
And another here:
return A(0) == A(0);
These are implicit because you are not explicitly telling the compiler that you want to convert the result of the comparisons to boolean_type and bool respectively. These implicit conversions are not allowed because you made both the constructor and conversion operator of boolean_type explicit - that's the whole point of the explicit keyword.
You would need to do:
return static_cast<boolean_type>(i_ == _other.i_);
And:
return static_cast<bool>(A(0) == A(0));
The typical reason for making conversions to bool explicit is because the conversion may be used in situations that you did not intend it to be used. For example, if you had boolean_type objects called b1 and b2 with non-explicit conversions, you would be able to do the following:
b1 > 0
b1 == b2
These are probably not the intended uses of the boolean conversion operator.
Why there are not explicit conversion here in both cases?
Because the onus is on you, the programmer, to be explicit if you want an explicit conversion.
Implicit conversions would work in this case if you had allowed them. But you didn't allow them when you marked operator bool and boolean_type::boolean_type as explicit.
Why are implicit?
Because you did not write the conversion. You must:
boolean_type operator == (A const & _other) const
{
return boolean_type (i_ == _other.i_);
}
...and:
bool t()
{
return (bool) (A(0) == A(0));
}
But what the risk here?
You tell us. explicit exists specifically to tell the compiler that there might be a risk in permitting some implicit conversions to take place. So when you marked those functions as explicit you said to the compiler:
Ok, if you allow an implicit conversion from a bool to a
boolean_operator or vice versa, something bad might happen. So don't
allow those implicit conversions.
You didn't tell the compiler (or us) why those implicit conversions are dangerous. You only said that they were.
Is it possible to change the behavior of if() so that:
class Foo {
int x;
};
Foo foo;
if(foo)
only proceeds if the value of x is something other than zero? or...
Would an explicit user-defined type conversion to int work/would that be an appropriate approach? or...
Is it best to do something like if(foo.getX())?
You can convert your object to a boolean value by defining operator bool():
explicit operator bool() const
{
return foo.getX();
}
The explicit keyword prevents implicit conversions from Foo to bool. For example, if you accidentally put foo in an arithmetic expression like foo + 1, the compiler could detect this error if you declare operator bool() as explicit, otherwise foo will be converted to bool even if not intended.
In general, member functions of the form
operator TypeName()
(with optional explicit and const qualifier) are conversion operators. It allows you to cast your class to any type specified by TypeName. In the other direction, constructors with one argument allow you to cast any type to your class:
class Foo {
Foo(int x); // convert int to Foo
operator bool() const; // convert Foo to bool
int x;
};
This defines implicit conversions for your class. The compiler tries to apply these conversions if possible (like what it does for built-in data types, e.g. 5 + 1.0). You can declare them to be explicit to suppress unwanted implicit conversions.
You can define an operator to convert the object to bool
class Foo
{
int x;
public:
operator bool() const
{
return x > 0;
}
};
But this can have unintended consequences because of implicit conversions to bool when you don't desire the conversion to take place. For instance
int x = 42 + Foo();
C++11 solves this problem by allowing you to declare the conversion operator as explicit, which then only allows implicit conversions in certain contexts, such as within an if statement.
explicit operator bool() const // allowed in C++11
Now
int x = 42 + Foo(); // error, no implicit conversion to bool
int x = 42 + static_cast<bool>(Foo()); // OK, explicit conversion is allowed
With all of the fundamental types of C++, one can simply query:
if(varname)
and the type is converted to a boolean for evaluation. Is there any way to replicate this functionality in a user-defined class? One of my classes is identified by an integer, although it has a number of other members, and I'd like to be able to check if the integer is set to NULL in such a manner.
Thanks.
The C++11 approach is:
struct Testable
{
explicit operator bool() const
{ return false; }
};
int main ()
{
Testable a, b;
if (a) { /* do something */ } // this is correct
if (a == b) { /* do something */ } // compiler error
}
Note the explicit keyword which prevents the compiler from converting implicitly.
You can define a user-defined conversion operator. This must be a member function, e.g.:
class MyClass {
operator int() const
{ return your_number; }
// other fields
};
You can also implement operator bool. However, I would STRONGLY suggest against defining conversion operators to integer types (including bool) because your class will become usable in arithmetic expressions which can quickly lead to a mess.
As an alternative, for example, IOStreams define conversion to void*. You can test void* in the same way you can test a bool, but there are no language-defined implicit conversions from void*. Another alternative is to define operator! with the desired semantics.
In short: defining conversion operators to integer types (including booleans) is a REALLY bad idea.
Simply implement operator bool() for your class.
e.g.
class Foo
{
public:
Foo(int x) : m_x(x) { }
operator bool() const { return (0 != m_x); }
private:
int m_x;
}
Foo a(1);
if (a) { // evaluates true
// ...
}
Foo b(-1);
if (b) { // evaluates true
// ...
}
Foo c(0);
if (c) { // evaluates false
// ...
}
As others have stated, using operator int () or operator bool () is bad idea because of the conversions it allows. Using a pointer is better idea. The best know solution to this problem so far is to return a member (function) pointer:
class MyClass {
void some_function () {}
typedef void (MyClass:: * safe_bool_type) ();
operator safe_bool_type () const
{ return cond ? &MyClass::some_function : 0; }
};
C++ checks if the statements result is whether equal to zero nor not. So i think you can define equality operator for your class and define how your class will be different from zero in which conditions.