Target-typing in modern C++
Solution 1:
In C++, expressions have types.
{}
is not, however, an expression. There are a handful of restricted contexts where {}
could be used when you'd expect an expression should go there. This doesn't make {}
into an expression.
?:
is an operation, and its arguments must have types. The type of ?:
is derived from the type of its 2 arguments (the rules are complex, but it tries to find a common type).
b ? std::optional{5} : std::nullopt;
is similar to what you want. Here, the fact that std::nullopt
can convert to a std::optional<int>
is used to deduce the type of ?:
expression.
You can also write:
template<class T>
std::optional<std::decay_t<T>> maybe( bool b, T&& t ) {
if (!b) return std::nullopt;
return std::forward<T>(t);
}
which lets you write
maybe( b, 5 )
for your case.
Fancier things can be done, where you use template<class T> operator T()
on a type to deduce the type you are returning into.
But, in general, the C++ type system goes one way.