The problem here is that the lambda is not an std::function, so you're asking the compiler to do a deduction (find the type of Arg AND Ret) and a convertion i.e. convert the lambda to an std::function. The combination causes a conflict.
If you want to still use std::function as argument type for fun, then the easier thing to do is to make a utility that identifies what std::function to cast your callable to, e.g.:
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&std::decay_t<F>::operator())>::type
function_from(F&& func)
{
return std::forward<F>(func);
}
which you'd use as
fun(function_from(f)); // Auto-detect <Ret(Args...)> types.
Demo
After showing the mechanics of how auto-detection works, note that from C++17 onwards the CTAD feature does this for you. So in newer compilers this also works:
fun(std::function(f)); // Again no types specified.
Alternatively, you can make your f a bit more generic and use just the argument deduction, like:
template <class F>
auto fun(F &&fun)
{
int x=0;
return std::invoke(std::forward<F>(fun), x);
};
fun(f); // Call directly with your lambda
Demo
Using c++20 concepts, this version can be restricted to the argument and input function types that you want.