这个问题完全是关于 std::function
而不是 boost::function
.有关详细信息,请参阅此问题底部的 更新 部分,尤其是关于无法比较非空 std::function
的部分符合 C++11 标准的对象。
C++11 std::function
类模板非常适合维护回调集合。可以将它们存储在 vector
,例如并在需要时调用它们。然而,维护这些对象并允许注销似乎是不可能的。
让我具体一点,想象一下这个类:
class Invoker
{
public:
void Register(std::function<void()> f);
void Unregister(std::function<void()> f);
void InvokeAll();
private:
// Some container that holds the function objects passed to Register()
};
示例使用场景:
void foo()
{
}
int main()
{
std::function<void()> f1{foo};
std::function<void()> f2{[] {std::cout << "Hello\n";} };
Invoker inv;
// The easy part
// Register callbacks
inv.Register(f1);
inv.Register(f2);
// Invoke them
inv.InvokeAll();
// The seemingly impossible part. How can Unregister() be implemented to actually
// locate the correct object to unregister (i.e., remove from its container)?
inv.Unregister(f2);
inv.Unregister(f1);
}
很清楚Register()
可以实现功能。但是,如何实现 Unregister()
.假设保存函数对象的容器是 vector<std::function<void()>>
.如何找到传递给 Unregister()
的特定函数对象?称呼? std::function
确实提供了一个过载的 operator==
,但这仅测试空函数对象(即,它不能用于比较两个非空函数对象以查看它们是否都引用相同的实际调用)。
我会很感激任何想法。
更新:
目前的想法主要包括添加一个与每个 std::function
相关联的 cookie。可用于注销它的对象。我希望有一些与 std::function
无关的东西对象本身。此外,std::function
之间似乎存在很多混淆。和 boost::function
.这个问题完全是关于 std::function
对象,而不是 boost::function
对象。
另外,你不能比较两个非空的 std::function
平等的对象。根据标准,他们总是会比较不相等。因此,在此问题的上下文中,解决方案的评论中的链接(并使用 boost::function
启动对象)显然是错误的。
最佳答案
由于您无法测试容器中的元素标识,因此最好使用一个容器(例如 std::list
),其迭代器不会在修改容器时失效,并且将迭代器返回给注册调用者,这些调用者可用于取消注册。
如果你真的想使用vector
(或deque
),你可以在添加回调时将整数索引返回到vector/deque。这种策略自然会要求您确保以这种方式使用索引来识别函数在序列中的位置。如果回调和/或注销很少见,这可能仅仅意味着不重复使用点。或者,您可以实现一个空闲列表来重用空槽。或者,仅从序列末尾回收空槽,并保持一个基本索引偏移量,当槽从开头回收时增加。
如果您的回调访问模式不需要随机访问遍历,则将回调存储在 std::list
中并使用原始迭代器取消注册对我来说似乎是最简单的。
关于c++ - std::function 作为回调,是否可以注销?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15916175/