问题严格关注std::function而非关键boost::function.有关详细信息,请参阅此问题底部的" 更新"部分,尤其是有关无法std::function根据C++ 11标准比较非空对象的部分.
C++ 11 std::function类模板非常适合维护一组回调.vector例如,可以将它们存储在a中,并在需要时调用它们.但是,维护这些对象并允许取消注册似乎是不可能的.
让我具体一点,想象一下这堂课:
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()
};
Run Code Online (Sandbox Code Playgroud)
示例使用场景:
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);
}
Run Code Online (Sandbox Code Playgroud)
很清楚如何实现该Register()功能.但是,如何实施呢Unregister()?假设持有函数对象的容器是vector<std::function<void()>>.您如何找到传递给Unregister()调用的特定函数对象?std::function确实提供了一个重载operator==,但只测试一个空函数对象(即,它不能用于比较两个非空函数对象,看它们是否都引用相同的实际调用).
我很感激任何想法.
更新:
到目前为止的想法主要包括添加一个cookie,该cookie与std::function可用于取消注册的每个对象相关联.我希望std::function对象本身不是外生的东西.此外,似乎有太大的混乱std::function和boost::function.问题严格来说是std::function对象,而不是 boost::function对象.
此外,您无法比较两个非空std::function对象的相等性.它们总是按照标准比较不相等.因此,在boost::function这个问题的上下文中,注释中的链接到那些(并使用对象引导)的解决方案显然是错误的.
Ada*_*son 11
由于您无法在容器中测试元素标识,因此最好使用容器(例如std::list),其容器在修改容器时不会失效,并将迭代器返回到注册可用于取消注册的调用者.
如果你真的想使用vector(或deque),你可以在添加回调时将积分索引返回到vector/deque中.这种策略自然要求您确保以这种方式使用索引来识别函数在序列中的位置.如果回调和/或取消注册很少,这可能只是意味着不重复使用点.或者,您可以实现一个空闲列表来重用空插槽.或者,仅从序列的末端回收空槽并保持基本索引偏移量,当从开头开始回收槽时,该偏移量会增加.
如果您的回调访问模式不需要随机访问遍历,那么将回调存储在a中std::list并使用原始迭代器进行取消注册对我来说似乎最简单.