为C++实现一个IDL (二)

说明:
要看懂后面那部分代码,即使用Typelist的部分,最好预先看过《C++设计新思维》,英文版名为《Modern C++ Design》。
If模板类在写完后想起来好像在哪见过,早晨去公司查阅了一下,在《产生式编程——方法、工具与应用》一书中有讲,英文名为《Generative Programming -- Methods, Tools, and Applications》基本和本篇中一个样。


前2篇乱七八糟地讲了一些,有一个遗留问题,函数原型的推导。

简要描述如下:

Method  <   void ( in < int > in < char > , inout < string > out < short > >  method;

//  同步调用
string  str  =   " hello " ;
short  value  =   2 ;
method (
3 ' a ' , str, value );

//  异步调用1
method.async_call ( 3 ' a ' " hello " );

//  异步调用2
void  test_func ( int char string short );
method.async_call (
3 ' a ' " hello " , test_func);


要产生这3种函数形式。参数类型如何转换,是以后的话题,本篇主要解决异步调用的函数原形推导问题。本篇也不讨论Method的模板参数(即那个函数类型)返回类型不为void的情况。

第一种形式,同步调用,比较好处理,参数个数和模板参数的数量相同。

后2种形式,如何让编译器根据in/out来推导出函数原型?

我们需要编译器做这样的处理,async_call的参数类型中,in类型的参数将保留,out类型的参数不需要,inout类型也需要保留。

要用到的Loki头文件:

#include  < static_check.h >
#include 
< Typelist.h >

using   namespace  Loki;
using   namespace  Loki::TL;


首先看看in/inout/out的声明。为了简化,这里去掉了跟类型推导无关的部分。

class  NullType
{
    NullType ();
};

template 
< class  T >
struct   in
{
    typedef T OriginalType;
};

template 
< class  T >
struct   out
{
    typedef T OriginalType;
};

template 
< class  T >
struct  inout
{
    typedef T OriginalType;
};

下面Method模板类的声明,使用偏特化来产生代码。为了简化,我只取函数参数个数为4个参数的版本,比照着上面的代码来解释,只解释method.async_call (3, 'a', "hello", test_func);这个版本,因为另一个比它简单。

template  < class  T >
struct  Method
{
};

template 
< class  Ret,  class  A,  class  B,  class  C,  class  D >
struct  Method  < Ret(A,B,C,D) >  
{
};


根据上面Method的定义,Method < void(in<int>, in<char>, inout<string>, out<short>) > ,async_call函数的类型将是:

typedef  void  ( * FUNC_TYPE)( int char string short );
void  async_call ( int char string , FUNC_TYPE func);

实际上FUNC_TYPE应该能够接受更广泛的类型,比如void(int, char, char*, short),这可以在内部做一些转换,不过本篇的重点不在这里,所以只讲上面的那种形式。

直接在Method类中实现有些麻烦,所以我把这个函数放在一个基类中实现,只要编译器能帮我们推导出下面这种形式就行了:

template  < class  Ret,  class  A,  class  B,  class  C,  class  D >
struct  Method  < Ret(A,B,C,D) >  :  public  Base  <  A, B, C  >
{
};


注意,这里是以Method < void(in<int>, in<char>, inout<string>, out<short>) >这种形式来讲的,才会有上面那种继承关系。而实际上,由于in/out在参数中的位置、数量都是未知的,要到定义时才能确定,所以使用模板来推导。(入正题了)

也就是说,只要我们能使用静态推导方式,获得A,B,C,D这四个参数中所有的in类型,把它交给Base作为模板参数就成了。

这里需要一个辅助的模板类,用来在编译时帮助推导:

template  < class  T >
class  InOutTypeTraits
{
    Loki::CompileTimeError 
< false >  Not_Supported_Type;
};

template 
< class  T >
struct  InOutTypeTraits  <   in < T >   >
{
    
enum  {isin = 1 , isout = 0 };
};

template 
< class  T >
struct  InOutTypeTraits  <   out < T >   >
{
    
enum  {isin = 0 , isout = 1 };
};

template 
< class  T >
struct  InOutTypeTraits  <  inout < T >   >
{
    
enum  {isin = 1 , isout = 1 };
};

template 
<>
struct  InOutTypeTraits  <  NullType  >
{
    
enum  {isin = 0 , isout = 0 };
};

通过另一个模板类InList来帮我们产生所有的in类型,它的结果是一个Typelist。为了方便以后使用,我把out类型产生器也做了一个OutList。

template  < int  CONDITION,  class  _IF,  class  _ELSE >
struct  If
{
    typedef _IF Result;
};

template 
< class  _IF,  class  _ELSE >
struct  If  < 0 , _IF, _ELSE >
{
    typedef _ELSE Result;
};

template 
< class  A  =  NullType,  class  B  =  NullType,  class  C  =  NullType,  class  D  =  NullType, 
    
class  E  =  NullType,  class  F  =  NullType,  class  G  =  NullType,  class  H  =  NullType
>
struct  InList
{
    typedef typename If 
<  
        InOutTypeTraits 
< A > ::isin,
        typename Typelist 
<  A, typename InList < B,C,D,E,F,G > ::Result  >
        typename InList
< B,C,D,E,F,G,H > ::Result 
    
> ::Result Result;
};

template 
< class  A >
struct  InList  < A, NullType, NullType, NullType, NullType, NullType, NullType, NullType >
{
    typedef typename If 
<
        InOutTypeTraits 
< A > ::isin,
        typename MakeTypelist 
< A > ::Result,
        typename MakeTypelist 
<> ::Result
    
> ::Result Result;
};

template 
< class  A  =  NullType,  class  B  =  NullType,  class  C  =  NullType,  class  D  =  NullType, 
    
class  E  =  NullType,  class  F  =  NullType,  class  G  =  NullType,  class  H  =  NullType
>
struct  OutList
{
    typedef typename If 
<  
        InOutTypeTraits
< A > ::isout,
        typename Typelist 
<  A, typename OutList < B,C,D,E,F,G > ::Result  >
        typename OutList
< B,C,D,E,F,G,H > ::Result 
    
> ::Result Result;
};

template 
< class  A >
struct  OutList  < A, NullType, NullType, NullType, NullType, NullType, NullType, NullType >
{
    typedef typename MakeTypelist 
< A > ::Result Result;
};

它的原理是,根据If模板类来判断一个类型是不是in类型,是的话就把它加入到Typelist中,不是就排除它。

InList <in<int>, in<char>, inout<string>, out<short>::Result是一个Typelist <in<int>, Typelist<in<char>, Typelist<inout<string>, NullType> > >类型,说简单点,它和MakeTypelist < in<int>, in<char>, inout<stirng> >::Result是等价的。

现在Base模板类将接受一个模板参数,它是一个Typelist类型,这个不详细讲了,把它的定义写出来:

template  < class  T,  int  T_COUNT  =  Length  < IN_TYPE > ::value  >
struct  Base
{
    Loki::CompileTimeError 
< false >  Only_Use_Partial_Specialisation_Version;
};

template 
< class  T >
struct  Base  < T,  0 >
{
    typedef 
void ( * FUNC_TYPE)();

    template 
< class  FUNC_TYPE >
    
void  async_call (FUNC_TYPE func)
    {
    }
    
void  async_call ()
    {
    }
};

template 
< class  T >
struct  Base  < T,  1 >
{
    typedef 
void ( * FUNC_TYPE)(
        typename TypeAt 
< T,  0 > ::Result::OriginalType);

    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0,
        FUNC_TYPE func)
    {
    }
    
void  async_call (typename TypeAt  < T,  0 > ::Result::OriginalType v0)
    {
    }
};

template 
< class  T >
struct  Base  < T,  2 >
{
    typedef 
void ( * FUNC_TYPE)(
        typename TypeAt 
< T,  0 > ::Result::OriginalType,
        typename TypeAt 
< T,  1 > ::Result::OriginalType);

    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0, 
        typename TypeAt 
< T,  1 > ::Result::OriginalType v1, 
        FUNC_TYPE func)
    {
    }
    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0, 
        typename TypeAt 
< T,  1 > ::Result::OriginalType v1)
    {
    }
};

template 
< class  T >
struct  Base  < T,  3 >
{
    typedef 
void ( * FUNC_TYPE)(
        typename TypeAt 
< T,  0 > ::Result::OriginalType, 
        typename TypeAt 
< T,  1 > ::Result::OriginalType,
        typename TypeAt 
< T,  2 > ::Result::OriginalType);

    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0, 
        typename TypeAt 
< T,  1 > ::Result::OriginalType v1, 
        typename TypeAt 
< T,  2 > ::Result::OriginalType v2, 
        FUNC_TYPE func)
    {
    }
    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0,
        typename TypeAt 
< T,  1 > ::Result::OriginalType v1,
        typename TypeAt 
< T,  2 > ::Result::OriginalType v2)
    {
    }
};

template 
< class  T >
struct  Base  < T,  4 >
{
    typedef 
void ( * FUNC_TYPE)(
        typename TypeAt 
< T,  0 > ::Result::OriginalType, 
        typename TypeAt 
< T,  1 > ::Result::OriginalType,
        typename TypeAt 
< T,  2 > ::Result::OriginalType,
        typename TypeAt 
< T,  3 > ::Result::OriginalType);

    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0, 
        typename TypeAt 
< T,  1 > ::Result::OriginalType v1, 
        typename TypeAt 
< T,  2 > ::Result::OriginalType v2, 
        typename TypeAt 
< T,  3 > ::Result::OriginalType v3,
        FUNC_TYPE func)
    {
    }
    
void  async_call (
        typename TypeAt 
< T,  0 > ::Result::OriginalType v0,
        typename TypeAt 
< T,  1 > ::Result::OriginalType v1,
        typename TypeAt 
< T,  2 > ::Result::OriginalType v2,
        typename TypeAt 
< T,  3 > ::Result::OriginalType v3)
    {
    }
};

这部分有点多,其实还是比较清晰的。注意这个Base的版本已经不是上面所讲的那个了。

函数原形推导问题就讲完了。上面的代码不一定还能编译,昨天是能编译的,被我修改了一些,为了解释,又改成昨天那样子。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值