For error 1, what's happening is that the compiler is attempting to substitute for T
in std::function
, but it cannot because ultimately a function pointer and a std::function
are different types, and there's no conversion defined for a function pointer to std::function
This worked:
std::function<double(std::vector<int>)> barz = bar<int, double>
Because std::function
was cleverly written with type-erasure to have a constructor that can accept any callable that is convertible to the type it needs. Note that this isn't the same as type-deduction in the above error because here we are already specifying the template arguments for std::function
.
Note that we can do a little work to get Foo::std_function
to work properly. First change its signature to take a forwarding reference:
template <class T>
void std_function(T&& functor){/*I'll talk about this in a bit*}
Then we can construct our std::function
internally (What you're looking to pass into it, I don't know) by using some helper structs to determine its type. For a function pointer we can do the following:
// base
template<class... T>
struct function_type_impl;
// specialization for function ptrs and static class fns
template<class Ret, class... Args>
struct function_type_impl<Ret(*)(Args...)>
{
using type = std::function<Ret(Args...)>;
};
// type alias so we don't need to keep typing typename ... ::type
template<class... T>
using function_type = typename function_type_impl<std::decay_t<T>...>::type;
and then we can modify our std_function
signature:
template <class T>
void std_function(T&& functor)
{
function_type<T> myFunction = std::forward<T>(functor);
// do something with our std::function
}
Then you can call it as
test.std_function(&::bar<int, double>);
However, if we want to be more complete, and accept functors, lambdas, and even other std::functions
, we can add more specializations:
namespace detail
{
template<class... T>
struct function_type_impl;
template<class Callable>
struct function_type_impl<Callable>
{
using type = typename function_type_impl<decltype(&Callable::operator())>::type;
};
template<class C, class Ret, class... Args>
struct function_type_impl<Ret(C::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<class Ret, class... Args>
struct function_type_impl<Ret(*)(Args...)>
{
using type = std::function<Ret(Args...)>;
};
template<class... T>
using function_type = typename function_type_impl<std::decay_t<T>...>::type;
}// detail namespace
And now the following will work, too:
struct MyFunctor
{
double operator()(std::vector<int>) const
{
return 42;
}
};
struct MyFunctor2
{
static double foo(std::vector<int>)
{
return 42;
}
};
int main()
{
Foo<double> test;
std::function<double(std::vector<int>)> barz = bar<int, double>;
test.std_function(&::bar<int, double>);
test.std_function(barz);
test.std_function([](std::vector<int>)->double{return 42;});
test.std_function(MyFunctor{});
test.std_function(MyFunctor2::foo);
}
Live Demo
For errors 2::1 and 2::2, the issue is simpler; functions do not exist at all until they're completely instantiated. That is, you cannot create a function pointer to a partially templated function. You have to specify all the template arguments when trying to get a function pointer. Since you have already specified the return type, you can allow the compiler to instantiate the rest of the pointer for you if you explicitly tell func_ptr
what to deduce for T
:
test.func_ptr<int>(bar);