C++模板类型匹配在RPC分发中的应用研究


最近研究了一下MammothServer,发现里面有一个叫Dispatcher的实现,很有意思。正好自己最近在学习boost::mpl等东东,因此花了几天学习,并把自己的学习心得总结了一下。相信对大多数C++程序员会有帮助。

前言

在编写通讯框架时,经常要处理众多的协议。而处理完协议后,再调用相应的处理函数时,
在C++中,我们一般要使用统一接口。比如Windows消息中的MSG结构等等。
这种统一的处理结构最大的缺点是缺乏有效地类型检测,容易出错。因为,编译器无法对每一个特定消息进行数据合法性检查。

不过利用模板技术,完全可以实现RPC参数的解析以及与C++函数的自动匹配,支持不定长参数。

伪代码
C++代码
  1. class Dispatcher {   
  2.     map<string, func> invokers_;   
  3.     void register_function( const std::string& name, func);   
  4.     void invoke( void* packet ) {   
  5.        sequence params = deserialize( packet );   
  6.        invokers_[ params["name"] ]( params );   
  7.     }   
  8. }   
  9.   
  10. void hello(const std::string& msg ) {   
  11. }   
  12. void hello2(const std::string& msg , const std::string& from) {   
  13. }   
  14.   
  15. Dispatcher.register_function("hello", hello );   
  16. Dispatcher.register_function("hello2", hello2 );  


准备知识

C++ template
boost::bind
boost::function      仿函数
boost::fusion         处理不同类型参数的sequence
boost::mpl             处理函数参数表的推导


part1 - basic framework

由于用户提供的函数带有不确定个数的参数,因此,在dispatcher内部,需要首先将用户提供的Function转换成为统一参数的仿函数,定义如下:
引用 出于讲解的需要,暂时不支持返回值,且与应用相关的参数被简化为一个void*

C++代码 复制代码
  1. typedef boost::function<void(void*)> invoker_function_type;  

相应的容器为
C++代码 复制代码
  1. typedef std::map<std::string, invoker_function_type> dictionary_type;  


注册函数考虑面向对象,因此包含函数Function和类实例Base.

C++代码
  1. class Dispatcher {   
  2.     // 实际的invoke函数形式   
  3.     typedef boost::function<void(void*)> invoker_function_type;   
  4.     // name -> invoker 表   
  5.     typedef std::map<std::string, invoker_function_type> dictionary_type;   
  6.   
  7.     dictionary_type m_invokers;   
  8.   
  9. public:   
  10.     template<typename Function, typename Base>   
  11.     void register_function(std::string const & name, Function f, Base& base) {   
  12.         m_invokers[name] = ...;  //TODO   
  13.     }   
  14. };  



part2 - invoker

invoker是整个实现的核心。其中最重要的是对用户调用函数参数的自适应。

C++代码 复制代码
  1. // predefinition   
  2. template<typename Function   
  3. ,typename From = typename mpl::advance_c<typename mpl::begin< ft::parameter_types<Function> >::type, 1>::type   
  4. ,typename To = typename mpl::end< ft::parameter_types<Function> >::type   
  5. >   
  6. struct Invoker;   
  7.   
  8. // invoker,提取参数,放入sequence,继续调用   
  9. template<typename Function   
  10.     ,typename From   
  11.     ,typename To   
  12. >   
  13. struct Invoker   
  14. {   
  15.     static void apply(Function func) {   
  16.         typedef typename mpl::deref<From>::type arg_type;        // 当前参数类型   
  17.         typedef typename mpl::next<From>::type next_iter_type;    // 下一个参数   
  18.   
  19.         typedef Invoker<Function, next_iter_type, To>    NextInvoker;   
  20.         NextInvoker::apply(func);   
  21.     }   
  22. };   
  23.   
  24. // 特化的invoker,结尾   
  25. template<typename Function   
  26. ,typename To   
  27. >   
  28. struct Invoker<Function,To,To>   
  29. {   
  30.     static void apply(Function func) {   
  31.         std::cout << "finish";   
  32.     }   
  33. };   
  34.   
  35. template<typename Function>   
  36. void trigger(Function func) {   
  37.   
  38.     Invoker<Function>::apply( func );   
  39. }  

不准确,但是直观的的描述可以理解为:
如果 函数为 func( int, char,void*),则实际生成的模板类分别是

C++代码 复制代码
  1. Invoker< Function, int , void >;   
  2. Invoker< Function, charvoid >;   
  3. Invoker< Function, void*, void >;   
  4. Invoker< Function, voidvoid >;  //* 这个会匹配到特化的Invoker,从而结束递归  


加入收集参数的模板参数
C++代码 复制代码
  1. // invoker,提取参数,放入sequence,继续调用   
  2. template<typename Function   
  3.     ,typename From   
  4.     ,typename To   
  5. >   
  6. struct Invoker   
  7. {   
  8.     templatetypename Args >   
  9.     static void apply(Function func, Args args) {   
  10.         typedef typename mpl::deref<From>::type arg_type;        // 当前参数类型   
  11.         typedef typename mpl::next<From>::type next_iter_type;    // 下一个参数   
  12.   
  13.         typedef Invoker<Function, next_iter_type, To>    NextInvoker;   
  14.         NextInvoker::apply(func, fusion::push_back(args,std::string("hello")));   
  15.     }   
  16. };   
  17.   
  18. // 特化的invoker,结尾   
  19. template<typename Function   
  20. ,typename To   
  21. >   
  22. struct Invoker<Function,To,To>   
  23. {   
  24.     templatetypename Args >   
  25.     static void apply(Function func,Args args) {   
  26.         std::cout << args;   
  27.         fusion::invoke(func, fusion::push_front(args, input));  // 完成对用户函数的调用   
  28.     }   
  29. };   
  30.   
  31. template<typename Function>   
  32. void trigger(Function func) {   
  33.     Invoker<Function>::apply( func , fusion::nil() );   
  34. }  


进一步实现对参数的提取,就可以实现一个完整的RPC的机制。

相关内容