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.