才想起來像這樣“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