Make a function accepting an optional to accept a non-optional?

  • A+

I'm trying to write syntactic sugar, in a monad-style, over std::optional. Please consider:

template<class T> void f(std::optional<T>) {} 

As is, this function cannot be called with a non-optional T1 (e.g. an int), even though there exists a conversion from T to std::optional<T>2.

Is there a way to make f accept an std::optional<T> or a T (converted to an optional at the caller site), without defining an overload3?

1) f(0): error: no matching function for call to 'f(int)' and note: template argument deduction/substitution failed, (demo).
2) Because template argument deduction doesn't consider conversions.
3) Overloading is an acceptable solution for a unary function, but starts to be an annoyance when you have binary functions like operator+(optional, optional), and is a pain for ternary, 4-ary, etc. functions.


Instead of taking optional as argument take deductible template parameter:

template<class T> struct is_optional : std::false_type{};  template<class T> struct is_optional<std::optional<T>> : std::true_type{};  template<class T, class = std::enable_if_t<is_optional<std::decay_t<T>>::value>> constexpr decltype(auto) to_optional(T &&val){     return std::forward<T>(val); }  template<class T, class = std::enable_if_t<!is_optional<std::decay_t<T>>::value>> constexpr std::optional<std::decay_t<T>> to_optional(T &&val){     return { std::forward<T>(val) }; }  template<class T> void f(T &&t){     auto opt = to_optional(std::forward<T>(t)); }  int main() {     f(1);     f(std::optional<int>(1)); } 

Live example


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: