When How to Use Explicit Operator Bool Without a Cast

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 a std::unique_ptr), it may be contextually converted. Also, the return value of a NullablePointer's equality and inequality operators must be contextually convertible to bool.


  •    std::remove_if(first, last, [&](auto){ return t; });

    In any algorithm with a template parameter called Predicate or BinaryPredicate, the predicate argument can return a T.


  •    std::sort(first, last, [&](auto){ return t; });

    In any algorithm with a template parameter called Compare, the comparator argument can return a T.

(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 to bool and is well-formed if and only if the
declaration bool t(e); is well-formed, for some invented temporary variable t

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 declaration bool 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



Leave a reply



Submit