【问题标题】:C++ Event template classC++ 事件模板类
【发布时间】:2015-10-21 09:10:44
【问题描述】:

我想像这样编写一个类似 C# 的 C++ 事件类:

template< typename ListenerType >
class Event
{
private:

    std::vector< ListenerType * > m_aListeners;

public:

    void operator += ( ListenerType * pListener )
    {
        m_aListeners.push_back( pListener );
    }

    void operator -= ( ListenerType * pListener )
    {
        std::vector< ListenerType * >::reverse_iterator revIter = m_aListeners.rbegin();
        for( ; revIter != m_aListeners.rend(); ++revIter )
            if( revIter == pListener )
            {
                m_aListeners.remove( revIter );
                break;
            }
    }
};

class DataReceivedEvent : public Event< DataReceivedListener >
{
public:

    void Trigger( const byte_t * pData )
    {
        for( size_t nI = 0; nI < m_aListeners.size(); ++nI )
            m_aListeners[ nI ]->OnDataReceived( pData );
    }
}

问题在于它迫使我编写一个 Trigger 方法,该方法总是为每种事件类型执行相同的操作(迭代和调用处理程序),因为不同的事件可以有不同的参数列表,并且对于每个事件,关联的处理程序类型有一个具有特定名称的方法。

我对 C++11 了解不多,但我感觉可以避免使用模板为每种事件类型重写 Trigger 方法。 但是我不能使用 C++11,所以我想知道是否有一种方法,使用旧的 C++ 版本,以一种类型安全的方式来做到这一点。

编辑:我考虑过创建事件数据类的层次结构,即template&lt; typename ListenerType &gt;::DataDataReceivedEvent::Data : public template&lt; typename ListenerType &gt;::Data,这样我就可以拥有一个始终采用单个参数的触发器方法,即virtual void Trigger( const Data * pData )。但是我还是有问题,它需要在事件监听器中调用特定的方法。

【问题讨论】:

  • 你可以使用 Boost 吗?因为那时您可以使用Boost functionBoost bind 库。
  • @JoachimPileborg 感谢您之前的评论 (stackoverflow.com/questions/14189440/…)。 VS2005似乎支持它,所以我会看看这个。而且我不想使用 boost,因为我的目标平台是 Android(没问题)和 Windows CE(boost 不太支持)。
  • 何不幸的是 VS2005 不支持函数和绑定 :( 但也许我仍然可以找到一种兼容的方法来处理 &lt;functional&gt; 中存在的内容

标签: c++ class templates events


【解决方案1】:

您也可以为此使用模板和运算符重载。当您假设ListenerType 实现operator() 时,您可以这样实现(示例还使用variadic templates。您可以使用任意数量的参数):

#include <vector>
#include <iostream>

template< typename ListenerType >
class Event
{
private:

    std::vector< ListenerType * > m_aListeners;

public:

    void operator += ( ListenerType * pListener )
    {
        m_aListeners.push_back( pListener );
    }

    void operator -= ( ListenerType * pListener )
    {
        auto revIter = m_aListeners.rbegin();
        for( ; revIter != m_aListeners.rend(); ++revIter )
            if( revIter == pListener )
            {
                m_aListeners.remove( revIter );
                break;
            }
    }

    template<typename... Params>
    void operator()(Params... data) {
        for (auto l : m_aListeners) {
            (*l)(data...);
        }
    }
};

class DataReceivedListener {
public:

    void operator()(const char* pData) {
        std::cout << pData << std::endl;
    }

};

class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
};


int main() {

    DataReceivedEvent e;
    DataReceivedListener l1;
    DataReceivedListener l2;
    e += &l1;
    e += &l2;

    e("Hello");
}

很遗憾,C++11 没有引入Concepts。如果你有这个 (constraints in C#),你会得到编译器的更多帮助。

【讨论】:

  • 感谢您的帮助!但不幸的是我不能使用 C++11。
  • 好的。您可以删除这些点,它应该适用于 C++98
猜你喜欢
  • 2015-03-18
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多