在便编译期间侦测可转换性和继承性

在C++中侦测转换能力的想法是:合并运用sizeof和重载函数,面对两个陌生的类型T和U, 我们想在编译期间发掘U是否继承自T,意味着不必使用dynamic_cast耗损执行期效率, 发掘这种继承关系, 靠的是用来侦没可转换性机制和威力惊人的sizeof操作符. sizeof用在任何表达式,可以感知重载、模板具现、转换规则以及任何可以发生在C++表达式身上的机制,并且会直接传回大小,不需拖到执行期评估

#include <vector>
#include <iostream>

template <class T,class U>
class Conversion{
    typedef char Small;
	class Big{char dummy[16];};
	
	static Small Test(U);
	static Big Test(...);
	static T Maker();
	
public:
    enum{exists=sizeof(Test(Maker()))==sizeof(Small)};
	enum{exists=(exists&&Conversion<U,T>::exists)};
	enum{sameType=false};
};

template <class T>
class Conversion<T,T>
{
public:
    enum{exists=1,exists2Way=1,sameType=1};
};

class Base
{
    char* member;
};

class Super:public Base{
    char* superMember;
};

#define SUPERSUBCLASS(BASE, SUPER)         ( (Conversion<const SUPER*, const BASE*>::exists ) && !(Conversion<const BASE*, const void*>::sameType ) )
#define SUPERSUBCLASS_STRICT(BASE, SUPER)  ( SUPERSUBCLASS(BASE, SUPER) && !(Conversion<const BASE, const SUPER>::sameType) )


#int main(int argc, char* ardv[])
{
    using namespace std;
	cout<<Conversion<double,int>::exists<<"\t"
	    <<Conversion<char,char*>::exists<<"\t"
	    <<Conversion<size_t,vector<int> >::exists<<"\t"
		<<endl;
	
     cout<<"SUPERSUBCLASS(double, int) "<<SUPERSUBCLASS(double, int)<<"\n"
        <<"SUPERSUBCLASS(Base, Super) "<<SUPERSUBCLASS(Base, Super)<<"\n"
        <<"SUPERSUBCLASS(Super, Base) "<<SUPERSUBCLASS(Super, Base)<<"\n"
        <<"SUPERSUBCLASS(char, char*) "<<SUPERSUBCLASS(char, char*)<<"\n"
        <<"SUPERSUBCLASS(char *, void*) "<<SUPERSUBCLASS(char *, void*)<<"\n"
        <<"SUPERSUBCLASS(void *, void*) "<<SUPERSUBCLASS(void *, void*)<<"\n"
        <<"SUPERSUBCLASS(size_t, vector<int>) "<<SUPERSUBCLASS(size_t, vector<int>)<<"\n"
        <<endl;
 
    cout<<"SUPERSUBCLASS_STRICT(double, int) "<<SUPERSUBCLASS_STRICT(double, int)<<"\n"
        <<"SUPERSUBCLASS_STRICT(Base, Super) "<<SUPERSUBCLASS_STRICT(Base, Super)<<"\n"
        <<"SUPERSUBCLASS_STRICT(Super, Base) "<<SUPERSUBCLASS_STRICT(Super, Base)<<"\n"
        <<"SUPERSUBCLASS_STRICT(char, char*) "<<SUPERSUBCLASS_STRICT(char, char*)<<"\n"
        <<"SUPERSUBCLASS_STRICT(char *, void*) "<<SUPERSUBCLASS_STRICT(char *, void*)<<"\n"
        <<"SUPERSUBCLASS_STRICT(void *, void*) "<<SUPERSUBCLASS_STRICT(void *, void*)<<"\n"
        <<"SUPERSUBCLASS_STRICT(size_t, vector<int>) "<<SUPERSUBCLASS_STRICT(size_t, vector<int>)<<"\n"
        <<endl;
 
    return 0;
}
	

 根据示例,我们需要分析编译期间侦测可转换型和继承性两个方面 

(一)首先进行编译期间可转换性的分析

(1)我们提供两个重载函数

Small   Test(U)   //该重载函数接受转换目标的U类型

Big       Test(...)  //接受任何其他类型

我们以类型T的临时对象来调用这些重载函数,接受U的那个函数Small Test(U)被调用,我们就知道类型T可以转换为类型U;否则如果调用Big 则类型T无法转换为U类型。为知道那个重载函数被调用,我们队重载函数的返回值定义了不同的大小和类型,并以sizeof来区分大小,其中,类型本省无关紧要,重要的是他们的大小必须保证不同,这里用Small和Big满足约束条件,在C++中调用本实例的重载函数Big Test的结果会如何并不知道,但是我们此处不真正调用这个重载函数,它甚至没有被实例化,因为sizeof并不对它求值。

我们传一个对象给Teat(),并使用sizeof在函数的返回值,代码可以写成const  bool  convExists= ( sizeof(Test(T())) == sizeof(Small) );由于类型T可能将自己的默认构造函数设为private,此时T()会编译失败,由于sizeof不会对任何表达式求值,此处我们使用的解决方法是strawman function方法返回一个T类型对象,即实现如下代码

 T  MakeT();

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

此处需要注意的是,像MakeT()和Test()不只没做任何事情,甚至根本没有被实例化,根本不真正存在。

(2)在类型T和类型U之间可能存在双向转换或者相同类型。示例中我们使用exists2Way 表示类型T和类型U之间是否可以双向转换,如果exists2Way = true表示可以双向转换;使用sameType表示类型T和类型U是否相同类型,如果sameType = true表示是相同类型。在如下代码部分是我们的功能代码

template <class T, class U>
class Conversion
{
        ... 
    enum { exists2Way = (exists && Conversion<U, T>::exists) };
    enum { sameType = false};
};

我们同时需要使用模板partial  spacialization显示实例化Conversion来实现sameType = true的相同类型版本,如下功能代码

template <class T>
class Conversion<T, T>
{
public:
    enum { exists = 1, exists2Way = 1, sameType = 1};
};

 类型相同肯定存在双向转换,这样我们就成功实现功能代码。

 

(3)编译期间可转换性的输出结果的分析,相关的输出结果是:1   0    0 ; 这个结果是由代码 

int main(int argc, char* argv[])
{
    using namespace std;
    cout<<Conversion<double, int>::exists<<"\t"
        <<Conversion<char, char*>::exists<<"\t"
        <<Conversion<size_t, vector<int> >::exists<<"\t"
        <<endl;
    ...
}

  

(二)类型的继承性分析,在C++,子类的指针可以安全的转换到基类指针

...
#define SUPERSUBCLASS(BASE, SUPER)         ( (Conversion<const SUPER*, const BASE*>::exists ) && !(Conversion<const BASE*, const void*>::sameType ) )
#define SUPERSUBCLASS_STRICT(BASE, SUPER)  ( SUPERSUBCLASS(BASE, SUPER) && !(Conversion<const BASE, const SUPER>::sameType) )
 
...
 
    cout<<"SUPERSUBCLASS(double, int) "<<SUPERSUBCLASS(double, int)<<"\n"
        <<"SUPERSUBCLASS(Base, Super) "<<SUPERSUBCLASS(Base, Super)<<"\n"
        <<"SUPERSUBCLASS(Super, Base) "<<SUPERSUBCLASS(Super, Base)<<"\n"
        <<"SUPERSUBCLASS(char, char*) "<<SUPERSUBCLASS(char, char*)<<"\n"
        <<"SUPERSUBCLASS(char *, void*) "<<SUPERSUBCLASS(char *, void*)<<"\n"
        <<"SUPERSUBCLASS(void *, void*) "<<SUPERSUBCLASS(void *, void*)<<"\n"
        <<"SUPERSUBCLASS(size_t, vector<int>) "<<SUPERSUBCLASS(size_t, vector<int>)<<"\n"
        <<endl;
 
    cout<<"SUPERSUBCLASS_STRICT(double, int) "<<SUPERSUBCLASS_STRICT(double, int)<<"\n"
        <<"SUPERSUBCLASS_STRICT(Base, Super) "<<SUPERSUBCLASS_STRICT(Base, Super)<<"\n"
        <<"SUPERSUBCLASS_STRICT(Super, Base) "<<SUPERSUBCLASS_STRICT(Super, Base)<<"\n"
        <<"SUPERSUBCLASS_STRICT(char, char*) "<<SUPERSUBCLASS_STRICT(char, char*)<<"\n"
        <<"SUPERSUBCLASS_STRICT(char *, void*) "<<SUPERSUBCLASS_STRICT(char *, void*)<<"\n"
        <<"SUPERSUBCLASS_STRICT(void *, void*) "<<SUPERSUBCLASS_STRICT(void *, void*)<<"\n"
        <<"SUPERSUBCLASS_STRICT(size_t, vector<int>) "<<SUPERSUBCLASS_STRICT(size_t, vector<int>)<<"\n"
        <<endl;
 
...

  实现两个类型的继承判断,输出结果为:

SUPERSUBCLASS(double, int) 0
SUPERSUBCLASS(Base, Super) 1
SUPERSUBCLASS(Super, Base) 0
SUPERSUBCLASS(char, char*) 0
SUPERSUBCLASS(char *, void*) 0
SUPERSUBCLASS(void *, void*) 1
SUPERSUBCLASS(size_t, vector<int>) 0
 
SUPERSUBCLASS_STRICT(double, int) 0
SUPERSUBCLASS_STRICT(Base, Super) 1
SUPERSUBCLASS_STRICT(Super, Base) 0
SUPERSUBCLASS_STRICT(char, char*) 0
SUPERSUBCLASS_STRICT(char *, void*) 0
SUPERSUBCLASS_STRICT(void *, void*) 0
SUPERSUBCLASS_STRICT(size_t, vector<int>) 0

根据结果可以知道,版本SUPERSUBCLASS(BASE, SUPER)在类型U是public继承自类型T,或者类型T和类型U是同一类型时,返回true.当SUPERSUBCLASS(BASE, SUPER)对const U*和const T*做"可转换性"评估时, 只有如下三种情况const U*可以隐式转换成const T*:

 1.  T和U是同一类型。

 2.  T是U的一个unambiguous(非歧义的)  public  base.

 3.  T是void

版本SUPERSUBCLASS_STRICT(BASE, SUPER)能够更好的区别出继承关系。其中我们在代码前都加上const 是因为template代码实施const两次,第二个会被忽略,这样就不会因为const而导致转型失败。

    在使用以上判定继承性的时候,我们只能判定以public方式继承的子类,这是一个比较遗憾的缺陷。同时声明了explicit 默认构造函数的类型,也会对断定方法造成很大的影响,因为protected 或者private的默认构造函数,可能会造成sizeof操作符 can not access member或者inaccessible.

 

 

posted @ 2014-11-09 15:32  liaotingpure  阅读(270)  评论(0编辑  收藏  举报