Overload resolution occurs only when (a) you are calling the name of a function/operator, or (b) are casting it to a pointer (to function or member function) with an explicit signature.
Neither is occurring here.
std::function takes any object that is compatible with its signature. It doesn't take a function pointer specifically. (a lambda is not a std function, and a std function is not a lambda)
Now in my homebrew function variants, for signature R(Args...) I also accept a R(*)(Args...) argument (an exact match) for exactly this reason. But it means that it elevates "exact match" signatures above "compatible" signatures.
The core problem is that an overload set is not a C++ object. You can name an overload set, but you cannot pass it around "natively".
Now, you can create a pseudo-overload set of a function like this:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
this creates a single C++ object that can do overload resolution on a function name.
Expanding the macros, we get:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
which is annoying to write. A simpler, only slightly less useful, version is here:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
we have a lambda that takes any number of arguments, then perfect forwards them to baz.
Then:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
works. We defer overload resolution into the lambda that we store in fun, instead of passing fun an overload set directly (which it cannot resolve).
There has been at least one proposal to define an operation in the C++ language that converts a function name into an overload set object. Until such a standard proposal is in the standard, the OVERLOADS_OF macro is useful.
You could go a step further, and support cast-to-compatible-function-pointer.
struct baz_overloads {
template<class...Ts>
auto operator()(Ts&&...ts)const
RETURNS( baz(std::forward<Ts>(ts)...) );
template<class R, class...Args>
using fptr = R(*)(Args...);
//TODO: SFINAE-friendly support
template<class R, class...Ts>
operator fptr<R,Ts...>() const {
return [](Ts...ts)->R { return baz(std::forward<Ts>(ts)...); };
}
};
but that is starting to get obtuse.
Live example.
#define OVERLOADS_T(...) \
struct { \
template<class...Ts> \
auto operator()(Ts&&...ts)const \
RETURNS( __VA_ARGS__(std::forward<Ts>(ts)...) ); \
\
template<class R, class...Args> \
using fptr = R(*)(Args...); \
\
template<class R, class...Ts> \
operator fptr<R,Ts...>() const { \
return [](Ts...ts)->R { return __VA_ARGS__(std::forward<Ts>(ts)...); }; \
} \
}