Search code examples
c++templatesc++17option-typetemplate-argument-deduction

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


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.


Solution

  • Another version. This one doesn't involve anything:

    template <typename T>
    void f(T&& t) {
        std::optional opt = std::forward<T>(t);
    }
    

    Class template argument deduction already does the right thing here. If t is an optional, the copy deduction candidate will be preferred and we get the same type back. Otherwise, we wrap it.