模板 std::函数作为类成员函数C++
Template std::function as class member function C++
我想将 std::function 作为成员存储在类中。
在调用 a.callMethod() 时,我在以下测试代码中遇到了麻烦,该方法之前已使用 a.setMethod() 设置。如果我删除模板,代码工作正常。
我尝试使用函数调用MethodOutsideClass进行调试,但没有成功。
有没有更好的方法来管理它?
#include <iostream>
#include <vector>
#include <functional>
template<typename T>
struct A
{
A(size_t size, T value) : vec_(size, value), method_(nullptr) {}
void setMethod(const std::function<int(A<T>&)> method) { method_ = method; }
int callMethod()
{
if(method_)
return method_(*this);
else
std::cerr << "method not initialized" << std::endl;
return -1;
}
std::vector<int> vec_;
std::function<int(A<T>& a)> method_;
};
template<typename T>
int callMethodOutsideClass(struct A<T>& a, const std::function<int(A<T>&)> method)
{
return method(a);
}
template<typename T>
int apple(struct A<T>& a)
{
a.vec_[0] += 1;
return 1;
}
template<typename T>
int orange(struct A<T>& a)
{
a.vec_[0] += 2;
return 2;
}
int main()
{
A<int> a(10,4), b(10,4);
std::cout << callMethodOutsideClass(a, &apple) << std::endl;
a.setMethod(&orange);
std::cout << a.callMethod() << std::endl;
std::cout << a.vec_[0] << std::endl;
}
我目前收到以下错误:
Foo6.cpp: In function ‘int main()’:
Foo6.cpp:46:47: error: cannot resolve overloaded function ‘apple’ based on conversion to type ‘std::function<int(A<int>&)>’
std::cout << callMethodOutsideClass(a, &apple) << std::endl;
^
Foo6.cpp:48:21: error: no matching function for call to ‘A<int>::setMethod(<unresolved overloaded function type>)’
a.setMethod(&orange);
^
Foo6.cpp:48:21: note: candidate is:
Foo6.cpp:9:7: note: void A<T>::setMethod(std::function<int(A<T>&)>) [with T = int]
void setMethod(const std::function<int(A<T>&)> method) { method_ = method; }
^
Foo6.cpp:9:7: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘std::function<int(A<int>&)>’
指向函数的指针不是std::function<T>
。std::function<T>
签名不能根据作为参数给出的函数地址来推断。此外,编译器无法解析适当的函数模板专用化,以便在请求转换为 std::function<T>
时获取其地址,因为 std::function<T>
的构造函数也是函数模板。
你需要更明确:
std::cout << callMethodOutsideClass<int>(a, &apple<int>) << std::endl;
// ^^^^^ ^^^^^
a.setMethod(&orange<int>);
// ^^^^^
<小时 />有没有办法"轻松"推断模板参数?
您可以通过以下两种方式之一修改callMethodOutsideClass
的签名:
选项#1:
禁用std::function<int(A<T>&)>
参数的类型推断:
template <typename T> struct identity { using type = T; };
template<typename T>
int callMethodOutsideClass(A<T>& a, const typename identity<std::function<int(A<T>&)>>::type method)
{
return method(a);
}
但是您必须为std::function
应用的类型擦除付费。
选项#2:
让编译器推导出作为参数给出的函子对象的真实类型:
template <typename T, typename F>
int callMethodOutsideClass(A<T>& a, F&& method)
{
return std::forward<F>(method)(a);
}
在这两种情况下,您都可以说:
callMethodOutsideClass(a, &apple<int>);
// ^^^^^
注意:您仍然必须通过提供模板参数列表来传递具体函数模板专用化的地址&apple<int>
。如果你想摆脱一个简单的&address
语法,那么采用它的函数需要声明该参数的确切类型:
template<typename T>
int callMethodOutsideClass(A<T>& a, int(*method)(A<T>&))
{
return method(a);
}
callMethodOutsideClass(a, &apple);
或者,您可以帮助编译器解决调用站点上的正确重载:
callMethodOutsideClass(a, static_cast<int(*)(decltype(a)&)>(&apple));
。或者,您可以使用定义如下的 Lambda 表达式:
template<typename T, typename F>
int callMethodOutsideClass(struct A<T>& a, F&& method)
{
return std::forward<F>(method)(a);
}
// in C++11:
callMethodOutsideClass(a, [](decltype(a)& x){return apple(x);});
// in C++14:
callMethodOutsideClass(a, [](auto&& x){return apple(std::forward<decltype(x)>(x));});
<小时 />就setMethod
成员函数而言,事情更容易,因为编译器确切地知道它期望const std::function<int(A<T>&)> method
已知(而不是推断T
的位置)。所以基本上,你只需要帮助编译器在调用站点获取你需要的函数模板专用地址:
a.setMethod(&orange<int>);
a.setMethod(static_cast<int(*)(decltype(a)&)>(&orange));
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针