`
qiezi
  • 浏览: 497721 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

    博客分类:
  • c++
阅读更多

说明:
要看懂后面那部分代码,即使用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 (intcharstringshort);
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)(intcharstringshort);
void async_call (intcharstring, 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的版本已经不是上面所讲的那个了。

函数原形推导问题就讲完了。上面的代码不一定还能编译,昨天是能编译的,被我修改了一些,为了解释,又改成昨天那样子。
分享到:
评论

相关推荐

    基于IDL和Visual_C++的混合编程

    在Windows操作系统环境下,实现IDL与Visual C++的混合编程主要有以下几种方法: 1. **动态链接库(Dynamic Link Library, DLL)调用** - IDL可以编译生成DLL文件,这些DLL文件可以在Visual C++中被调用。 - 通过...

    IDL接口定义语言的C++11语言映射规范(v1.0)

    C++ 11映射试图避免限制ORB开发人员的实现自由。对于每个OMG IDL构造,C++ 11映射解释使用C++ 11的构造的语法和语义。如果客户机或服务器程序使用C++ 11映射子句中所描述的结构,则符合此映射(是C++ 11)。

    servant C++语言框架rpc的源码实现 tools C++语言框架IDL工具的源码实现 util C++语言.7z

    tools C++语言框架IDL工具的源码实现 util C++语言框架基础工具库的源码实现 examples C++语言框架的示例代码,包括:快速入门示例、promise编程入门示例、压测程序示例 unittest tars cpp rpc框架的单元测试用例,...

    VC++调用IDL的使用案例

    这个接口定义了一个名为`IMyInterface`的方法`MyMethod`,接受一个long类型的参数并返回一个BSTR类型的值。 步骤2:编译IDL 使用MIDL工具,将`.idl`文件转换为C++代码。在命令行中,执行以下命令: ```bash midl ...

    Calling C from IDL(2002)

    《Calling C from IDL》是2002年发布的一份文档,主要探讨了如何在IDL(Interactive Data Language)环境中调用C和C++代码。IDL是一种强大的数据处理和可视化语言,广泛应用于科学计算和数据分析领域。而C和C++是...

    用C++实现Corba

    《用C++实现Corba》是一本针对初学者和进阶者全面介绍如何使用C++语言来实现CORBA(Common Object Request Broker Architecture,公共对象请求代理架构)的优秀教程。这本书详细阐述了CORBA的核心概念、设计原则以及...

    基于C++的CORBA实现

    - **多线程支持**:由于CORBA通常用于构建并发系统,因此C++实现时需考虑多线程问题,确保线程安全。 **3. CORBA的主要优点** - **平台和语言无关**:CORBA标准允许在不同操作系统和编程语言之间进行通信,促进了...

    IDL精髓.pdf

    例如,const修饰符用于声明常量,指出一个变量的值一旦被赋值后就不能被改变;signed和unsigned则分别用于指定有符号和无符号整型。修饰符在类型库中的描述情况和它们能修饰的类型范围是这类内容的关键知识点。 第9...

    omniorb idl 文件编译示例

    在这个例子中,`MyModule`模块包含一个名为`MyService`的接口,该接口有一个返回字符串的`sayHello`方法。 要使用omniORB编译这个IDL文件,你需要执行以下步骤: 1. **安装omniORB**: 首先,确保你的系统上已经...

    IDL精髓美 Martin Gudgin

    本书向读者提供了IDL的详细描述及如何使用IDL方面的知识,基于示例、由浅入深地阐述了各种IDL...第二部分的4个章节则提供了一个IDL类型、修饰符、关键字及属性的参考。 本书适合使用COM、微软事务服务器(MTS)、C++或

    基于IDL和VisualC_的混合编程

    - 示例:假设有一个IDL编写的用于数据预处理的程序,可以将其封装为一个DLL,然后在Visual C++中通过LoadLibrary和GetProcAddress等函数调用该DLL中的特定函数。 2. **COM组件技术**:利用IDL提供的COM组件功能,...

    C#与IDL混编实例

    4. **实现IDL服务端**:在服务端,需要使用与IDL兼容的语言(如C++或Java)实现接口,并启动服务监听客户端请求。 5. **通信机制**:C#客户端通过代理类与服务端通信,通常采用RPC(Remote Procedure Call)或者...

    基于C语言实现的IDL编译器.pdf

    基于C语言实现的IDL编译器的知识点主要包括以下几点: 1. CORBA规范:IDL编译器是基于公共对象请求代理结构(CORBA)规范实现的。CORBA规范是一种中间件标准,用于分布式对象计算。它允许透明地访问远程对象,并...

    c++开发一个简单累加的COM组件

    1. 创建COM项目:使用VS2010创建一个新的ATL COM项目,选择“Visual C++” --&gt; “ATL 项目”,填写项目名称为“FirstCOM”。 2. 添加COM接口:在类视图中,右键单击项目“FirstCOM” --&gt; “添加” --&gt; “类”,添加...

    IDL和Visual C混合编程

    这种方式通常通过创建一个DLL或者ActiveX控件来实现。 **2.1 创建动态链接库** - **编写DLL**:使用VC++编写DLL,并导出需要在IDL中使用的函数。 - **IDL中调用DLL**:在IDL程序中加载DLL并通过调用相应的函数来...

    idl.rar_IDl_idl POLYFILL_idl教程

    idl.rar 是一个包含有关IDL(Interface Definition Language)学习资源的压缩包文件,主要针对IDL的基础知识和Polyfill的使用。IDL通常用于定义不同软件组件之间的接口,尤其在分布式系统和跨平台应用程序中扮演着...

    归一化植被指数IDL程序实现

    归一化植被指数(Normalized Difference Vegetation Index, NDVI)是一种广泛应用在遥感...通过这些知识的学习和实践,初学者可以逐步掌握如何利用IDL和CUDA实现高效的NDVI计算,从而更好地进行植被监测和环境研究。

    IDL可视化分析与应用(随书程序)

    总之,《IDL可视化分析与应用》一书结合随书程序,为学习者提供了一个全面了解和实践IDL的平台,无论是初学者还是经验丰富的专业人士,都能从中获益匪浅,提升数据处理和可视化的专业能力。通过深入学习和实践这些...

    IDL.rar_IDl

    例如,给定一个`.idl`文件,源码生成器可以生成C++或Java类,这些类包含了与IDL定义相对应的函数和数据结构。 **使用过程** 1. **定义接口**:首先,开发者需要使用IDL语言编写接口定义文件,明确服务的输入、输出...

Global site tag (gtag.js) - Google Analytics