gpt4 book ai didi

c++ - 模板 std::function 作为类成员函数 C++

转载 作者:行者123 更新时间:2023-11-30 02:41:47 26 4
gpt4 key购买 nike

我想在类中存储一个 std::function 作为成员。
我在调用 a.callMethod() 时遇到以下测试代码的问题,其中该方法是在 a.setMethod() 之前设置的。如果我删除模板,代码可以正常工作。
我曾尝试使用函数 callMethodOutsideClass 进行调试,但没有成功。
有没有更好的方法来管理它?

#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>);
// ^^^^^

Is there any way to deduce templates parameters "easily" ?

可以修改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::function 作为类成员函数 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27680198/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com