// testing multicast: tagged & single parameter
{BtMulticast<void,int>test;test.AddFunc("a",[](intp){BT_LOG("Multicast (tagged): func a called (param: %d). ",p);});test.AddFunc("b",[](intp){BT_LOG("Multicast (tagged): func b called (param: %d). ",p);});test.AddFunc("c",[](intp){BT_LOG("Multicast (tagged): func c called (param: %d). ",p);});test.RemoveFunc("b");test.Invoke(15);}
// testing multicast with multiple parameters and return value list
{BtMulticast<int,int,int>testRet;testRet.AddFunc("a",[](intp1,intp2)->int{BT_LOG("Multicast (with RetVal): func a called (p1: %d, p2: %d). ",p1,p2);returnp1+1*p2;});testRet.AddFunc("b",[](intp1,intp2)->int{BT_LOG("Multicast (with RetVal): func b called (p1: %d, p2: %d). ",p1,p2);returnp1+2*p2;});testRet.AddFunc("c",[](intp1,intp2)->int{BT_LOG("Multicast (with RetVal): func c called (p1: %d, p2: %d). ",p1,p2);returnp1+3*p2;});testRet.RemoveFunc("b");for(auto&p:testRet.InvokeR(20,2))BT_LOG("Multicast (with RetVal): func %s returned %d. ",p.second,p.first);}
Multicast (with RetVal): func a called (p1: 20, p2: 2).
Multicast (with RetVal): func c called (p1: 20, p2: 2).
Multicast (with RetVal): func a returned 22.
Multicast (with RetVal): func c returned 26.
可以看到 BtMulticast 能够适配任意个数和类型的参数,因此可认为具有一定的通用性。
实现
最后我们简单看一下实现。先看看 BtMulticast::AddFunc(),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<typenameTRet,class... TArgs>boolBtMulticast<TRet,TArgs...>::AddFunc(conststd::string&tag,TFuncfunc){// check if this tag has been used
if(tag.size()){autoit=std::find_if(m_funcList.begin(),m_funcList.end(),[&tag](constTElem&elem){returnelem.second==tag;});if(it!=m_funcList.end())returnfalse;}m_funcList.emplace_back(func,tag);returntrue;}
当 tag 有效时,先判定是否有 tag 冲突,然后注册一下回调,过程很直白就不多说了。
再看一下具体的调用过程 BtMulticast::InvokeR(),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* ----- Note -----
`BtMulticastRetVect` is an extra alias especially for the returning type for the signature of InvokeR() below,
since `TRetVect` defined inside `BtMulticast` cannot be used in the signature (outside the function body)
although `BtMulticastRetVect` is defined separately, it literally equals to `typename BtMulticast::TRetVect`
*/template<typenameTRet>usingBtMulticastRetVect=std::vector<std::pair<TRet,std::string>>;template<typenameTRet,class... TArgs>template<class... U>BtMulticastRetVect<TRet>BtMulticast<TRet,TArgs...>::InvokeR(U&&...u){BtMulticastRetVect<TRet>ret;for(auto&p:m_funcList){ret.emplace_back(p.first(std::forward<U>(u)...),p.second);}returnret;}