When can I use explicit operator bool without a cast?
The standard mentions places where a value may be "contextually converted to bool
". They fall into four main groups:
Statements
if (t) /* statement */;
for (;t;) /* statement */;
while (t) /* statement */;
do { /* block */ } while (t);
Expressions
!t
t && t2
t || t2
t ? "true" : "false"
Compile-time tests
static_assert(t);
noexcept(t)
explicit(t)
if constexpr (t)
The conversion operator needs to be constexpr
for these.
Algorithms and concepts
NullablePointer T
Anywhere the Standard requires a type satisfying this concept (e.g. the
pointer
type of astd::unique_ptr
), it may be contextually converted. Also, the return value of aNullablePointer
's equality and inequality operators must be contextually convertible tobool
.std::remove_if(first, last, [&](auto){ return t; });
In any algorithm with a template parameter called
Predicate
orBinaryPredicate
, the predicate argument can return aT
.std::sort(first, last, [&](auto){ return t; });
In any algorithm with a template parameter called
Compare
, the comparator argument can return aT
.
(source1, source2)
Do be aware that a mix of const and non-const conversion operators can cause confusion:
- Why doesn't explicit bool() conversion happen in contextual conversion?
- Why does the
explicit operator bool
not in effect as expected?
C++: using class with explicit operator bool overloaded
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;
Why is my explicit operator bool() not called?
Because A()
is not const
, the operator int()
is selected. Just add const
to the other conversion operator and it works:
#include <iostream>
using namespace std;
struct A
{
explicit operator bool() const
{
std::cout << "bool: ";
return true;
}
operator int() const
{
std::cout << "int: ";
return 0;
}
};
int main()
{
if (A())
{
cout << "true" << endl;
}
else
{
cout << "false" << endl;
}
}
Live Example that prints: "bool: true" and without the const
it prints "int: false"
Alternatively, make a named constant:
// operator int() without const
int main()
{
auto const a = A();
if (a)
// as before
}
Live Example that prints "bool: true".
Why does an explicit operator bool let me cast to ANY primitive type?
This looks like a VS bug: the explicit operator is not supposed to apply in a cast to a type other than bool
.
This fails to compile in gcc in both C++11 mode and C++98 mode.
Can I do anything to prevent this?
You have done what you needed to do - it is a compiler's problem.
Explicit conversion operator bool
From [expr.log.or]:
The operands are both contextually converted to
bool
Contextual conversion to bool is allowed to use explicit conversions. That's the point of the concept of "contextuality": The explicit conversion is allowed precisely when it makes sense, and not otherwise, so you don't accidentally form arbitrary integral or pointer values from the bool conversion, but when you actually ask for a bool, you get it.
See [conv]/4 for details:
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
explicit specifier doesn't seem to work when converting an object to bool
Contextual conversion is special; since C++11, explicit
conversion functions will be considered in contextual conversions.
(emphasis mine)
(since C++11)
In the following contexts, the type
bool
is expected and the implicit conversion is performed if the declarationbool t(e);
is well-formed (that is, an explicit conversion function such as explicit T::operator bool() const; is considered). Such expression e is said to be contextually converted to bool.
- 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;
- the expression in an explicit specifier; (since C++20)
- the predicate of a contract attribute. (since C++20)
That means for if (b2)
, b2
will be converted to bool
implicitly by B::operator bool()
even it's declared as explicit
.
Why C++ 11 added operator bool to the ios classes
In C++98 there were no explicit
cast operators so if you had an operator bool
it meant that the object could be used as a bool
or anything that can be cast from bool
(such as int
) this meant that you could accidentally use your objects in ways that you wouldn't expect or want (such as obj + 2
). Some objects provided a cast to void*
which meant that the object could be tested in an if
statement (not null) but would not be passable to functions expecting int
etc.
With the introduction of explicit
cast operators this is no longer needed and in order to have a testable object it's much better to use explicit operator bool
than operator void*
.
Integer cast overload being used instead of bool cast overload
It seems that the object Menu1
is not a constant object. So to call the conversion operator to bool, one conversion to const is required, while to call the conversion operator to int, no conversion to const is required.
Declare both operators as constant member functions, and make them (or at least the conversion operator to int) explicit
, as it is shown in the demonstrative program below:
#include <iostream>
struct A
{
int x = 0;
explicit operator int() const
{
std::cout << "operator int() const is called\n";
return x;
}
explicit operator bool() const
{
std::cout << "operator bool() const is called\n";
return x != 0;
}
};
int main()
{
A a = { 10 };
if ( a ) std::cout << a.x << '\n';
return 0;
}
The program output is:
operator bool() const is called
10
Related Topics
Error Lnk2005: Already Defined - C++
Create a Function to Check for Key Press in Unix Using Ncurses
Allocating More Memory Than There Exists Using Malloc
Using Sizeof on Arrays Passed as Parameters
How to Declare a Member Vector of the Same Class
Detect 32-Bit or 64-Bit of Windows
Lifetime of a String Literal Returned by a Function
No Match for 'Operator<<' in 'Std::Operator
Std::Sort Does Not Always Call Std::Swap
Is the Pointer Guaranteed to Preserve Its Value After 'Delete' in C++
Matching Alias Template as Template Argument
How to Use Visual Studio Code to Compile Multi-Cpp File
Vector Push_Back Calling Copy_Constructor More Than Once
What's the Behavior of an Uninitialized Variable Used as Its Own Initializer