【发布时间】:2016-03-27 15:41:25
【问题描述】:
我想实现一个管理器,它使用 C++11 存储对多态类成员函数的回调。问题是我不知道如何处理成员所属的对象被删除或应该被删除的情况,我想让界面尽可能简单。
所以我想到了以下方法:将std::weak_ptr 存储到对象,并将std::function 存储到成员。
以下似乎有效:
class MyBase {
public:
MyBase() {}
virtual ~MyBase() {}
};
//--------------------------------------------------
class MyClass : public MyBase {
public:
MyClass() : MyBase() {}
void myDouble(double val) const { std::cout << "Value is: " << val << std::endl; }
};
//--------------------------------------------------
Class Manager {
public:
void setFunction(std::weak_ptr<MyBase> base, std::function<void(double)> func) {
m_function.first = base;
m_function.second = func;
}
private:
std::pair<std::weak_ptr<MyBase>, std::function<void(double)>> m_function;
};
要使用这个:
Manager db;
std::shared_ptr<MyClass> myClass = std::make_shared<MyClass>();
db.setFunction(myClass, std::bind(&MyClass::myDouble, myClass, std::placeholders::_1));
现在我想对用户隐藏std::bind部分,这样他只需要调用:
db.setFunction(myClass, &MyClass::myDouble);
所以我想在我的经理职能中实现以下工作:
void setFunc2(std::weak_ptr<MyBase> base, std::function<void(double)> func) {
m_function.first = base;
m_function.second = std::bind(func, base, std::placeholders::_1);
}
但上面给出了错误:
error: no match for 'operator=' (operand types are 'std::function<void(double)>' and
'std::_Bind_helper<false, std::function<void(double)>&, std::weak_ptr<MyBase>&, const std::_Placeholder<1>&>::type {aka std::_Bind<std::function<void(double)>(std::weak_ptr<MyBase>, std::_Placeholder<1>)>}')
m_function.second = std::bind(func, base, std::placeholders::_1);
有没有更好的方法来做到这一点,或者有办法让它发挥作用?
我注意到一些有趣的事情。如果我使用std::shared_ptr,则use_count() 会随着原始代码中对std::bind 的调用而递增。因此,除非我取消设置经理上的成员,否则我无法手动重置/销毁对象。这种行为记录在哪里,我通常使用cppreference?
我查看了以下问题,但似乎无法解决我的问题:How can I use polymorphism with std::function?
【问题讨论】:
-
关于 shared_ptr 使用计数,en.cppreference.com/w/cpp/utility/functional/bind 表示“std::bind 的返回类型为每个 args 保存 [...] 一个对象...,[...] 由 std ::forward
(arg_i)。”并在同一页面的下方“复制或移动要绑定的参数”。因为你传递了一个 shared_ptr 左值,所以你得到了一个副本。 -
&MyClass::myDouble无论如何都不会转换为std::function<void(double)>。 -
@T.C 我完全意识到这一点,因此是问题的原因。我不在乎签名是什么样子,我希望调用看起来像
db.setFunction(myClass, &MyClass::myDouble);
标签: c++ c++11 std-function stdbind