Loki库:类型间耦合检测和去耦合

转载 2005年05月07日 12:29:00

Loki库:类型间耦合检测和去耦合

 

      数据类型之间的联系主要有两类:一,类型之间存在着自动转换关系;二,类型间存在着继承关系,虽然它其实也表明了某种转换(主要是对象切片和指针向上映射)。

      那么,如何判断类型间存在转换或继承呢?LokiTypeManip提供了很精彩很完美的解决方法(注:《More Exceptional C++Item 4也给出了讲解,可以参考。):

 

//WQ注:和以前讨论过的TypeList一样,Conversion类也是供编译期使用

//的,所以靠提供萃取来解决问题的。

    template <class T, class U>

    struct Conversion

    {

        typedef Private::ConversionHelper<T, U> H;

#ifndef __MWERKS__

        //WQ注:这是精妙所在!讲解太长,放到后面进行。

        enum { exists = sizeof(typename H::Small) == sizeof(H::Test(H::MakeT())) };

#else

        enum { exists = false };

#endif

        enum { exists2Way = exists && Conversion<U, T>::exists };

        enum { sameType = false };

    };

    //WQ注:用偏特化解决相同类型

    template <class T>

    struct Conversion<T, T>   

    {

        enum { exists = 1, exists2Way = 1,sameType = 1 };

    };

    // WQ注:用偏特化和特化解决void

    template <class T>

    struct Conversion<void, T>   

    {

        enum { exists = 1, exists2Way = 0,sameType = 0 };

    };

   

    template <class T>

    struct Conversion<T, void>   

    {

        enum { exists = 1, exists2Way = 0,sameType = 0 };

    };

   

    template <>

    class Conversion<void, void>   

    {

    public:

        enum { exists = 1, exists2Way = 1,sameType = 1 };

    };   

}

 

先看辅助类ConversionHelper的定义:

        template <class T, class U>

        struct ConversionHelper

        {

            typedef char Small;

struct Big { char dummy[2]; };

//WQ注:注意,下面三个函数并没有实现体!

            static Big   Test(...);//WQ注:C++中,不定参数已不需要“至少一个定参”了。

            static Small Test(U);

            static T MakeT();

        };

看其中的Test函数,如果TU之间存在转换关系的话,根据重载决策,肯定调Big Test(U)函数。依靠两个函数的返回类型并不相同,就可以判断出调了那个版本,于是也就推测出TU之间是否存在转换关系了。

回过头来再看前面的使用:sizeof(typename H::Small) == sizeof(H::Test(H::MakeT()));由于我们讲过,Conversion是编译期使用的类,不想采用对返回值采用运行期比较运算,恰好有sizeof()运算满足要求。所以,ConversionHelper将两个Test函数的返回类型实现得在大小上不等。

令人崩溃的事来了:由于我们只使用了BigSmall的大小而没有用它的值,所以,可以根本不用真的创建返回对象,Test函数也不必真的被调用,于是所有行为都是编译期的了。C++说,你可以不用创建并没有被真的使用的东西,所以,Test函数可以不用被定义,只要有这个申明就行了。是的,Loki库中确实没有定义这三个函数!崩溃啊,崩溃!在没搞懂这一点之前,我反复搜索了全部源码,并认为我下载了一个不完全的版本,然后四处搜索最新版本,着实乱了好一阵。虽然我不敢说所有C++编译器都能支持这一点,但我使用的VCBCBDevCPP三个主流编译器都正确支持了这一点,Loki的源码能够正确编译和使用。

     如何判断两个类型间存在继承关系?很简单:派生类指针类型可以自动向上映射为基类指针类型。当然还得排除“同类型指针间”和“非void *void *间”这两种情况。Loki库源码如下:

////////////////////////////////////////////////////////////////////////////////

// macro SUPERSUBCLASS

// Invocation: SUPERSUBCLASS(B, D) where B and D are types.

// Returns true if B is a public base of D, or if B and D are aliases of the

// same type.

//

// Caveat: might not work if T and U are in a private inheritance hierarchy.

////////////////////////////////////////////////////////////////////////////////

 

#define SUPERSUBCLASS(T, U) /

    (::Loki::Conversion<const U*, const T*>::exists && /

    !::Loki::Conversion<const T*, const void*>::sameType)

 

////////////////////////////////////////////////////////////////////////////////

// macro SUPERSUBCLASS_STRICT

// Invocation: SUPERSUBCLASS_STRICT(B, D) where B and D are types.

// Returns true if B is a public base of D.

//

// Caveat: might not work if T and U are in a private inheritance hierarchy.

////////////////////////////////////////////////////////////////////////////////

 

#define SUPERSUBCLASS_STRICT(T, U) /

    (SUPERSUBCLASS(T, U) && /

!::Loki::Conversion<const T, const U>::sameType)//WQ注:有人指出此处最好使用const T *,const U *,但确实TU就足够了,只是编译耗时可能要多一点点,反正运行期都是没有任何开销。

      故事还没有结束,提供的萃取值是int01(当然也可以认为等价于boolfalsetrue),它们只能作运行期运算的,那么如何编译期使用这些结果?Loki库同样有精彩的解决方法:

////////////////////////////////////////////////////////////////////////////////

// class template Int2Type

// Converts each integral constant into a unique type

// Invocation: Int2Type<v> where v is a compile-time constant integral

// Defines 'value', an enum that evaluates to v

////////////////////////////////////////////////////////////////////////////////

 

    template <int v>

    struct Int2Type

    {

        enum { value = v };

};

////////////////////////////////////////////////////////////////////////////////

// class template Select

// Selects one of two types based upon a boolean constant

// Invocation: Select<flag, T, U>::Result

// where:

// flag is a compile-time boolean constant

// T and U are types

// Result evaluates to T if flag is true, and to U otherwise.

////////////////////////////////////////////////////////////////////////////////

 

    template <bool flag, typename T, typename U>

    struct Select  

    {

        typedef T Result;

    };

    template <typename T, typename U>

    struct Select<false, T, U>

    {

        typedef U Result;

};

    

Select,一个编译期的?:运算。编译期只能靠类型推导(模板),类型判决(重载)来选择不同的分支。Int01自然不在这两种情况之列,但Int2Type<0>Int2Type<1>当然是满足的。依靠偏特化,Select圆满完成了它的任务。

 

      类型之间有自动转换当然是极有用的,但很多时候却也造成麻烦:一,很容易产生转换多径,尤以多继承时最为麻烦;二,发生期望外的转换而得到期望外的行为,尤以重载时的情况最为混乱;三,转换不够精确,不能完全满足需要,问题发生在向下类型映射时。

      在适当的时候去除了类型间耦合就可以避免这三方面副作用。

      类型间去耦合有两种方法:一,用模板封装;二,指向指针的指针。

方法一的实现太简单了:

template<typename T>

struct Type2Type

{

    typedef  T  OriginalType;

}    

      多个T之间的转换和继承关系在Type2Type<T>之间再不存在了。更为神奇的是,向下类型映射将可以精确进行的,但这得结合其具体使用来讲,我把它留到下一篇《多继承的改良》中讲。


 

物联12:射频识别距离-耦合类型

在rfid系统中,读写器与电子标签之间是作用距离是射频识别应用的一个重要指标。     这个距离,与射频标签和读写器配合情况密切相关。根据系统作用距离的远近,标签天线与读写器之间耦合可以分为三种类型:...

关于即时通讯高度解耦合框架之一 适配器中不同类型消息框架

先介绍BaseHolder类,这个类是聊天类型的控件载体,包含通用的contentview,由initBaseHolder里面的参数传递 public class BaseHolder { ...
  • lzy20ls
  • lzy20ls
  • 2017年04月19日 23:03
  • 237

通过Java模拟各种类型的耦合

耦合性是用来描述模块之间的独立程度。这里讲模块之间的耦合程度分为六个程度R1.-R6(Ri >Rj, i > j)。分别是无耦合,数据耦合,标记耦合,控制耦合,共同耦合,内容耦合。...

CodeIgniter Model间调用和耦合性冲突问题

在一个Model中调用另一个Model的问题公司的框架是基于CI开发的。用着很舒服。这几天自已搞个东西用的CI,发现很多问 题,CI真的很不方便,问题很多。 CI模型中不对载入模型 比如在gam...

C++进阶 降低文件间的编译依存关系(接口与实现解耦合)

问题背景 有时候会发现仅仅改动了某个类的一点实现(仅仅是几句代码),在编译时却发现要编译整个工程!特别是工程有点大时,编译要等很久很久。。。只为修改一个问题,时间都浪费在等待上了。为了避免这一问题...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Loki库:类型间耦合检测和去耦合
举报原因:
原因补充:

(最多只允许输入30个字)