I do need std::function for stateful operation.
So I would like to make an instance of a class implementing operator()
into std::function
. I did test std::bind
works, but can't wrap it up as a function.
struct StatefulOperation
{
StatefulOperation(int num) : num_(num) {}
int operator()(int i)
{
num_ += i;
return num_;
}
int num_;
};
// This works
const StatefulOperation obj(40);
using std::placeholders::_1;
std::function<int(int)> op = std::bind(&StatefulOperation::operator(), obj, _1);
// Want something like this
template<typename A, typename B, typename C>
std::function<B(A)> op(C& obj);
// This doesn't work
template<typename A, typename B, typename C>
std::function<B(A)> op(C& obj)
{
using std::placeholders::_1;
return std::bind(&C::operator(), obj, _1);
}
The last implementation attempt fails with error like below;
main.cpp:52:21: note: template argument deduction/substitution failed:
main.cpp:75:35: note: couldn’t deduce template parameter ‘A’
75 | std::function<int(int)> f = op(a);
| ~~^~~
How can I get this done?
The compiler cannot deduce A
and B
just from the return type. You need to specify them:
std::function<int(int)> f = op<int, int>(a);
However, you don't really need these additional template parameters. Just use auto
to deduce the return type:
template<typename C>
auto op(C& obj)
{
using std::placeholders::_1;
return std::bind(&C::operator(), std::ref(obj), _1);
}
The return type will not be exactly the same, but convertible to what you want (std::function<B(A)>
). If you want to specify the exact return type, you can do so with a combination of this and std::invoke_result_t
.