Implicit conversion not allowed on return

From C++ docs:

When an object of type optional< T > is contextually converted to bool, the conversion returns true if the object contains a value and false if it does not contain a value.

Read about contextual conversions here:

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;

You can do the following hack:

bool f() {
    std::optional<int> opt;
    return opt || false;
}

because contextual conversion happens in case of the built-in logical operators, but contextual conversion does not include return statements and std::optional by itself does not have implicit conversion to bool.

Therefore, it would be the best to use the std::optional<T>::has_value:

bool f() {
    std::optional<int> opt;
    return opt.has_value();
}

std::optional doesn't have any facility for implicitly converting to bool. (Allowing implicit conversions to bool is generally considered a bad idea, since bool is an integral type so something like int i = opt would compile and do completely the wrong thing.)

std::optional does have a "contextual conversion" to bool, the definition of which looks similar to a cast operator: explicit operator bool(). This cannot be used for implicit conversions; it only applies in certain specific situations where the expected "context" is a boolean one, like the condition of an if-statement.

What you want is opt.has_value().


That's because implicit coversion of std::optional to bool is not supported: https://en.cppreference.com/w/cpp/utility/optional/operator_bool

constexpr explicit operator bool() const noexcept;

You have to explicitly convert to bool as bool(opt) or simply use opt.has_value() instead.


This isn't really about implicit conversion, this is about the type of initialization.

What optional has is an explicit conversion function, i.e.

explicit operator bool() const; 

From N4849 [class.conv.fct]/p2

A conversion function may be explicit (9.2.2), in which case it is only considered as a user-defined conversion for direct-initialization.

The above means that these cases will use the conversion function : [dcl.init]/p16

The initialization that occurs (16.1) — for an initializer that is a parenthesized expression-list or a braced-init-list, (16.2) — for a new-initializer (7.6.2.7), (16.3) — in a static_cast expression (7.6.1.8), (16.4) — in a functional notation type conversion (7.6.1.3), and (16.5) — in the braced-init-list form of a condition is called direct-initialization.

However, these cases will not use the conversion function : [dcl.init]/p15

The initialization that occurs in the = form of a brace-or-equal-initializer or condition (8.5), as well as in argument passing, function return, throwing an exception (14.2), handling an exception (14.4), and member initialization (9.4.1), is called copy-initialization.

The example in the question falls under the copy initialization case and does not use optional's conversion function.