Reputation: 458
If i have a template function in C++11, is it then possible to wrap it in a std::function
?
My problem is like this:
I have a generic function (say a sum function) where the return type depends on the types of the arguments:
template <typename T>
auto sum(T const& a, T const& b) -> decltype(a+b)
{
return a + b;
}
and I want to wrap it in a std:function
for specific argument types (say int). I'm trying the following:
int main()
{
std::function<int(int,int)> intsum = std::bind(static_cast<int(*)(int,int)>(&sum), std::placeholders::_1, std::placeholders::_2);
auto mysum = intsum(2, 4);
std::cout << mysum << std::endl;
return 0;
}
But compiling the above code produces an error:
error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘int (*)(int, int)
Is there some way to achieve what I am trying to do?
Upvotes: 3
Views: 1028
Reputation: 275730
Your problem is you got the type wrong.
There is no int(int,int)
overload of sum<?>
. So when you static_cast<int(*)(int,int)(sum)
, it complains that it cannot do the conversion.
There is a int(int const&,int const&)
overload. If you static_cast<int(*)(int const&, int const&)>(sum)
it would work.
Conversion of a function template to a pointer to function won't work if there is no such overload to point to.
There are three approaches that are reasonable.
First, cast to the right type. static_cast<int(*)(int const&,int const&)>(sum)
.
Second, explicitly specialize. sum<int>
instead of the static_cast
expression.
Third, create an overload set object:
struct sum_t{
template<class...Args>
auto operator()(Args&&...args)const
-> decltype(sum(std::declval<Args>()...))
{
return sum(std::forward<Args>(args)...);
}
};
static sum_t sum_os;
and replace static_cast<int(*)(int,int)>(sum)
with sum_os
.
sum_os
can be passed to bind
or std::function
or whatever, and the overload resolution is deferred until the invocation code.
As a bonus, it is easier for the compiler to optimize than a function pointer call.
As a negative, perfect forwarding is imperfect.
A C++14 version of the overload set is:
[](auto&&...args)->
decltype(sum(decltype(args)(args)...))
{ return sum(decltype(args)(args)...); }
which can be turned into a macro:
#define OVERLOAD_SET(FUNC) \
[](auto&&...args)-> \
decltype(FUNC(decltype(args)(args)...)) \
{ return FUNC(decltype(args)(args)...); }
which lets you simply do OVERLOAD_SET(sum)
at the point of use, and pass in the entire overload set.
Upvotes: 1
Reputation: 67772
You can't wrap a generic function in a specific instance of std::function
, which is what you asked for.
You can, however, wrap a fully-specified instance of a generic function, which is what your code is actually trying to do:
template <typename T>
auto sum(T const& a, T const& b) -> decltype(a+b)
{
return a + b;
}
#include <functional>
#include <iostream>
int main()
{
std::function<int(int,int)> intsum =
std::bind(sum<int>,
std::placeholders::_1, std::placeholders::_2);
auto mysum = intsum(2, 4);
std::cout << mysum << std::endl;
}
Or more simply
std::function<int(int,int)> intsum = sum<int>;
Or of course if you don't really need to wrap it, just:
auto mysum = sum(2, 4);
Upvotes: 2
Reputation: 65630
You can just specialize the template and use that:
std::function<int(int,int)> intsum = sum<int>;
auto mysum = intsum(2, 4);
std::cout << mysum << std::endl;
Upvotes: 4