1

我想编写一个最小的多播委托类。它的接口包含三个运算符 operator() 用于调用委托和 operator+=/operator-= 用于添加/删除可调用类型,如函数、方法、lambda 或仿函数。

我在实现 operator-= 时遇到了麻烦,我需要比较函数目标的地址以进行删除。到目前为止,这是我想出的(我使用 g++ 4.6.3):

#include <functional>
#include <list>

template <typename ... EventArgs>
class Event
{
public:
    typedef std::function<void (EventArgs...)> EventHandler;

    Event() = default;
    ~Event() = default;
    Event(const Event &) = delete;
    Event & operator=(const Event &) = delete;

    void operator()(EventArgs... eventArgs)
    {
        for (auto eventHandler : m_eventHandlers)
            eventHandler(eventArgs...);
    }

    Event & operator+=(const EventHandler &eventHandler)
    {
        m_eventHandlers.push_back(eventHandler);
        return *this;
    }

    Event & operator-=(const EventHandler &eventHandler)
    {
        m_eventHandlers.remove_if([&](const EventHandler &_eventHandler)
        {
            return false; // TODO: Compare event handlers
        });

        return *this;
    }

private:
    std::list<EventHandler> m_eventHandlers;
};

当我用以下代码替换 TODO 行时,operator-= 适用于函数:

return * eventHandler.template target<void (*)(EventArgs...)>() ==
       *_eventHandler.template target<void (*)(EventArgs...)>();

这是一个最小的例子:

void eventHandler() { /* ... */ }

Event<> event;
event += eventHandler;
event();
event -= eventHandler; // works

但是,对于其他可调用类型,它会崩溃,因为 std::function.target() 返回空指针。显然模板不再适合,所以我尝试模板 Event::operator-= 但由于“不完整类型”,它不能编译最可调用的类型:

template<typename T>
Event & operator-=(const T &eventHandler)
{
    m_eventHandlers.remove_if([&](const EventHandler &_eventHandler)
    {
        if (_eventHandler.template target<T>() != null_ptr) // <- ERROR
        {
            // ...
        }
    });

    return *this;
}    

我也尝试过 T* 作为 target() 的模板参数,但我被卡住了。是否可以编写一个通用 operator-= 来正确比较任何可调用类型?

提前致谢!

4

1 回答 1

3

问题是std::function<>不支持比较运算符==!=. boost::function对此有解释

一种解决方案是将函数存储在映射或以整数为键的哈希中。注册将返回该整数键。要取消注册,必须传递密钥,例如:

typedef int handler_id_t;
handler_id_t add(const EventHandler &eventHandler);
void del(handler_id_t);
于 2012-05-16T08:17:10.940 回答