Lambda is not std::function<> . A std::function<R(Args...)> is the value type of the erase type that can be stored by any object that is compatible with the R(Args...) code R(Args...)
In one case, above R there is void (which for a std::function means "I donโt care what it returns), and Args... is std::string . The called object is compatible with the call with this, if you can call its with std::string rvalue.
This applies to both std::optional<std::string> and std::string .
There is no special overload for โexact matchingโ - everything that matters is compatible with the call or not.
There are several ways to handle this.
template<std::size_t N> struct overload_order : overload_order<N-1> {}; template<> struct overload_order<0> {}; namespace details { void foo(overload_order<1>, fn_string) { cout << "string" << endl; } void foo(overload_order<0>, fn_optional_string) { cout << "optional string" << endl; } } template<class F> void foo(F&& f) { foo( overload_order<!std::is_same<std::decay_t<F>, fn_optional_string>{}>{}, std::forward<F>(f) ); }
now we will first try fn_string alone, and only if that fails, try fn_optional_string if the argument is no longer fn_optional_string , in which case we send directly to this overload.
source share