英文:
C++ template function from callable class instance to std::function
问题
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 an 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?
英文:
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?
答案1
得分: 2
编译器无法仅从返回类型中推断出A
和B
,您需要指定它们:
std::function<int(int)> f = op<int, int>(a);
然而,您实际上不需要这些额外的模板参数。只需使用auto
来推断返回类型:
template<typename C>
auto op(C& obj)
{
using std::placeholders::_1;
return std::bind(&C::operator(), std::ref(obj), _1);
}
返回类型不会完全相同,但可以转换为您想要的std::function<B(A)>
。如果您想指定确切的返回类型,可以结合使用this和std::invoke_result_t
来实现。
英文:
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
.
答案2
得分: 1
Instead of using bind you should use lambda expressions. Also you StatefulOperation should NOT be const (otherwise it can't update its internal state).
#include <functional>
#include <iostream>
struct StatefulOperation
{
StatefulOperation(int num) : num_(num) {}
int operator()(int i)
{
num_ += i;
return num_;
}
int num_;
};
int main()
{
/*const*/ StatefulOperation obj(40); // your state cannot be const since you are changing its internal state
// instead of bind rely on lambda expressions (bind is still there because of well... history)
std::function<int(int)> op{ [&](int num) { return obj(num); } };
for (int i = 0; i < 10; ++i)
{
std::cout << op(i) << " ";
}
return 0;
}
英文:
Instead of using bind you should use lambda expressions. Also you StatefulOperation should NOT be const (otherwise it can't update its internal state).
#include <functional>
#include <iostream>
struct StatefulOperation
{
StatefulOperation(int num) : num_(num) {}
int operator()(int i)
{
num_ += i;
return num_;
}
int num_;
};
int main()
{
/*const*/ StatefulOperation obj(40); // your state cannot be const since you are changing its internal state
// instead of bind rely on lambda expressions (bind is still there because of well... history)
std::function<int(int)> op{ [&](int num) { return obj(num); } };
for (int i = 0; i < 10; ++i)
{
std::cout << op(i) << " ";
}
return 0;
}
答案3
得分: 0
你可以用最简单的方式初始化一个std::function
,因为你的类是可调用的,实现了一个具有期望类型的函数调用运算符:
std::function<int(int)> op{StatefulOperation(40)};
不要忘记,当复制op
时,状态也会被复制。
英文:
Since your class is a callable that implements a function call operator with the expected types, you can initialize a std::function
in the most simple way:
std::function<int(int)> op{StatefulOperation(40)};
Do not forget that the state is copied when op
is copied.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论