C++事件机制实现的改进

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++事件机制实现的改进相关的知识,希望对你有一定的参考价值。

才想起来像这样“return void();”也是合法的,所以这次给事件加上返回值支持,而且之前事件声明语法很难看:

1 Event(int, int) event;

改成大众喜闻乐见的样子:

1 Event<void (int, int)> event;

不过需要自己实现的代码就增多不少,已经不能称之为简洁了。首先考虑返回值怎么表示,可以这样:

技术分享
 1 template<class P1>
 2 auto operator ()(P1 arg1) -> decltype(std::function<HandlerT>(arg1))
 3 {
 4     int j = m_handlers.size();
 5 
 6     for ( const auto& i : m_handlers )
 7     {
 8         if ( --j == 0 )
 9             return i.second(arg1);
10         else
11             i.second(arg1);
12     }
13 
14     return decltype(std::function<HandlerT>(arg1))();
15 }
技术分享

但是看起来很繁琐,用类型萃取把返回值类型取出来,还可以顺便把参数个数、每个参数的类型提取,这对扩展很有用(现在只用到返回值类型和参数个数):

技术分享
 1 // 萃取函数签名里的参数个数和返回值类型
 2 template<class R> struct ParamTraits { typedef void RetType; };
 3 template<class R> struct ParamTraits<R ()> { enum { num = 0 }; typedef R RetType; };
 4 template<class R, class P1> struct ParamTraits<R (P1)> { enum { num = 1 }; typedef R RetType; };
 5 template<class R, class P1, class P2> struct ParamTraits<R (P1, P2)> { enum { num = 2 }; typedef R RetType; };
 6 template<class R, class P1, class P2, class P3> struct ParamTraits<R (P1, P2, P3)> { enum { num = 3 }; typedef R RetType; };
 7 template<class R, class P1, class P2, class P3, class P4> struct ParamTraits<R (P1, P2, P3, P4)> { enum { num = 4 }; typedef R RetType; };
 8 template<class R, class P1, class P2, class P3, class P4, class P5> struct ParamTraits<R (P1, P2, P3, P4, P5)> { enum { num = 5 }; typedef R RetType; };
 9 template<class R, class P1, class P2, class P3, class P4, class P5, class P6> struct ParamTraits<R (P1, P2, P3, P4, P5, P6)> { enum { num = 6 }; typedef R RetType; };
10 template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7)> { enum { num = 7 }; typedef R RetType; };
11 template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7, P8)> { enum { num = 8 }; typedef R RetType; };
12 template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7, P8, P9)> { enum { num = 9 }; typedef R RetType; };
13 template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)> { enum { num = 10 }; typedef R RetType; };
技术分享

现在成了这样:

技术分享
 1 typedef typename Event_Private::ParamTraits<HandlerT>::RetType RetType;
 2 
 3 template<class P1>
 4 RetType operator ()(P1 arg1)
 5 {
 6     int j = m_handlers.size();
 7 
 8     for ( const auto& i : m_handlers )
 9     {
10         if ( --j == 0 )
11             return i.second(arg1);
12         else
13             i.second(arg1);
14     }
15 
16     return RetType();
17 }
技术分享

到这里,已经完成事件返回值的支持了,事件执行后取得最后一个事件处理器的返回值,如果没有绑定过,就返回返回值类型的默认值。如果不显式支持绑定类成员函数的话,到这一步已经足够了,但是还是要做一下。由于必须使用std::bind,而又不能摆脱参数占位符_1、_2...,只有依靠参数个数自动选择模板来实现了:

技术分享
 1 template<class HandlerT, int ParamNum> struct Helper {};    
 2 
 3 template<class HandlerT> struct Helper<HandlerT, 1>
 4 {
 5     template<class ObjT, class FuncT> 
 6     inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1))
 7     {
 8         return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1);
 9     }
10 }
技术分享

把 Ret operator()(P1,P2,...,Pn) 也放进去,使之从事件接口只看到对应参数个数的operator(),然后最外部加一层封装,隐藏参数个数选择的细节:

完整代码

///////////////////////////////////////////////////////////////////////
// 事件模板
//
// 版本: 1.2
//
// 说明: 事件可以有无返回值,支持0~10个参数;不判断事件处理函数是否已经绑定过;不是线程安全的;
//
// 使用:
//
//  void f1(int, int)
//  {
//      puts("f1()");
//  }
//  
//  struct F2
//  {
//      F2() { puts("F2 construct"); }
//      F2(const F2 &) { puts("F2 copy"); }
//      F2(F2 &&) { puts("F2 move"); }
//      F2& operator=(const F2 &)  { puts("F2 copy assign"); return *this; }
//      F2& operator=(F2 &&)  { puts("F2 move assign"); return *this; }
//  
//      void f(int, int)
//      {
//          puts("f2()");
//      }
//  
//      void fc(int, int) const
//      {
//          puts("f2c()");
//      }
//  };
//  
//  struct F3
//  {
//      F3() { puts("F3 construct"); }
//      F3(const F3 &) { puts("F3 copy"); }
//      F3(F3 &&) { puts("F3 move"); }
//      F3& operator=(const F3 &)  { puts("F3 copy assign"); return *this; }
//      F3& operator=(F3 &&)  { puts("F3 move assign"); return *this; }
//  
//      void operator ()(int, int) const
//      {
//          puts("f3()");
//      }
//  };
//  
//  int _tmain(int argc, _TCHAR* argv[])
//  {
//      Utility::Event<void (int, int)> e;
//  
//      // 一般函数
//      e.addHandler(f1);
//  
//      int id = e.addHandler(&f1);                                    
//      e.removeHandler(id);                                                // 移除事件处理函数
//  
//  
//      // 成员函数
//      using namespace std::placeholders;
//  
//      F2 f2;
//      const F2 *pf2 = &f2;
//  
//      e.addHandler(bind(&F2::f, &f2, _1, _2));        // std::bind
//      e.addHandler(&f2, &F2::f);
//  
//      e.addHandler(pf2, &F2::fc);                                    // 常量指针
//  
//      puts("----addHandler(f2, &F2::f)----");
//      e.addHandler(f2, &F2::f);                                        // 对象拷贝构造
//  
//      puts("----addHandler(F2(), &F2::f)----");
//      e.addHandler(F2(), &F2::f);                                    // 对象转移构造
//  
//      puts("--------");
//  
//  
//      // 仿函数
//      F3 f3;
//      const F3 *pf3 = &f3;
//  
//      puts("----addHandler(f3)----");
//      e.addHandler(f3);                                                        // 对象拷贝构造
//  
//      puts("----addHandler(F3())----");
//      e.addHandler(F3());                                                    // 对象转移构造
//      puts("--------");
//  
//      e.addHandler(ref(f3));                                            // 引用仿函数对象
//      e.addHandler(ref(*pf3));                                        // 引用仿函数常量对象
//  
//      puts("--------");
//  
//      // Lambda表达式
//      e.addHandler([](int, int) {
//          puts("f4()");
//      });
//  
//      // 激发事件
//      e(1, 2);
//  
//      return 0;
//  }
//
/////////////////////////////////////////////////////////////////////////

#pragma once

#include <map>
#include <functional>


namespace Utility
{

    namespace Event_Private
    {
        // 萃取T ()函数类型的参数个数和返回值类型
        template<class R> struct ParamTraits { typedef void RetType; };
        template<class R> struct ParamTraits<R ()> { enum { num = 0 }; typedef R RetType; };
        template<class R, class P1> struct ParamTraits<R (P1)> { enum { num = 1 }; typedef R RetType; };
        template<class R, class P1, class P2> struct ParamTraits<R (P1, P2)> { enum { num = 2 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3> struct ParamTraits<R (P1, P2, P3)> { enum { num = 3 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4> struct ParamTraits<R (P1, P2, P3, P4)> { enum { num = 4 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4, class P5> struct ParamTraits<R (P1, P2, P3, P4, P5)> { enum { num = 5 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4, class P5, class P6> struct ParamTraits<R (P1, P2, P3, P4, P5, P6)> { enum { num = 6 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7)> { enum { num = 7 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7, P8)> { enum { num = 8 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7, P8, P9)> { enum { num = 9 }; typedef R RetType; };
        template<class R, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10> struct ParamTraits<R (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)> { enum { num = 10 }; typedef R RetType; };

        // 事件辅助类
        template<class HandlerT, int ParamNum> struct Helper {};    
        

        // 事件模板基类
        template<class HandlerT>
        class EventBase
        {
        protected:
            typedef typename Event_Private::ParamTraits<HandlerT>::RetType RetType;

            int m_handlerId;
            std::map<int, std::function<HandlerT>> m_handlers;

        public:
            EventBase() : m_handlerId(0) {}

            template<class Func> int addHandler(Func func)
            {
                m_handlers.emplace(m_handlerId, std::forward<Func>(func));
                return m_handlerId++;
            }

            template<class ObjT, class Func> int addHandler(ObjT obj, Func func)
            {
                m_handlers.emplace(m_handlerId, Event_Private::Helper<HandlerT, Event_Private::ParamTraits<HandlerT>::num>::getBind(std::forward<ObjT>(obj), std::forward<Func>(func)));
                return m_handlerId++;
            }

            void removeHandler(int handlerId)
            {
                m_handlers.erase(handlerId);
            }
        };

    } // namespace Event_Private


    // 事件模板
    //
    template<class HandlerT>
    struct Event : public Event_Private::Helper<HandlerT, Event_Private::ParamTraits<HandlerT>::num>::Event_
    {
    };


    // 按调用参数个数区分的事件激发函数、类成员绑定对象
    namespace Event_Private
    {
        using namespace std::placeholders;

        template<class HandlerT> struct Helper<HandlerT, 0>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj)))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj));
            }

            struct Event_ : public EventBase<HandlerT>
            {
                RetType operator ()()
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second();
                        else
                            i.second();
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 1>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1>
                RetType operator ()(P1 arg1)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1);
                        else
                            i.second(arg1);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 2>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2>
                RetType operator ()(P1 arg1, P2 arg2)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2);
                        else
                            i.second(arg1, arg2);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 3>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3);
                        else
                            i.second(arg1, arg2, arg3);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 4>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4);
                        else
                            i.second(arg1, arg2, arg3, arg4);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 5>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4, class P5>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4, arg5);
                        else
                            i.second(arg1, arg2, arg3, arg4, arg5);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 6>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4, class P5, class P6>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4, arg5, arg6);
                        else
                            i.second(arg1, arg2, arg3, arg4, arg5, arg6);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 7>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4, class P5, class P6, class P7>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
                        else
                            i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 8>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
                        else
                            i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 9>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
                        else
                            i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
                    }

                    return RetType();
                }
            };
        };

        template<class HandlerT> struct Helper<HandlerT, 10>
        {
            template<class ObjT, class FuncT> 
            inline static auto getBind(ObjT obj, FuncT func) -> decltype(std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9, _10))
            {
                return std::bind(std::forward<FuncT>(func), std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9, _10);
            }

            struct Event_ : public EventBase<HandlerT>
            {
                template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>
                RetType operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9, P10 arg10)
                {
                    int j = m_handlers.size();

                    for ( const auto& i : m_handlers )
                    {
                        if ( --j == 0 )
                            return i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
                        else
                            i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
                    }

                    return RetType();
                }
            };
        };

    } // namespace Event_Private

} // namespace Utility

  

以上是关于C++事件机制实现的改进的主要内容,如果未能解决你的问题,请参考以下文章

Android ViewGroup事件分发机制

C++ 异常机制分析

反思|Android 事件拦截机制的设计与实现

node.js零基础详细教程:node.js事件机制node异步IO操作

扒去Spring事件监听机制的外衣,竟然是观察者模式

扒去Spring事件监听机制的外衣,竟然是观察者模式