2.7
编译期间侦测可转换性和继承性
在泛型编程中,经常遭遇一个问题:对于两个型别T和U,如何得知U是否继承于T。我们需要在编译时发现这样的关系,而不必使用dynamic_cast——它会损耗执行期效率。
我们利用sizeof
和 重载函数。比如如下定义两个类型,和两个函数,一个函数接收U类型,一个接收任意类型。
1 typedef char Small;
2 class Big {char dummy[2];};
3 Small Test(U);
4 Big Test();//省略号参数函数
我们传一个T类型对象给Test函数,看它能不能转换为U:
1 const bool convExists = sizeof(Test(T())) == sizeof(Small);
但如果T的缺省构造函数为私有,则会编译失败,所以我们用一个“稻草人函数”:
1 T MakeT();
2 const bool convExists = sizeof(Test(MakeT())) == sizeof(Small);
我们注意,sizeof()里面的东西不需要具现,所以T对象,MakeT()、Test()都不需要实作。它们根本不真正存在!!现在用class
template包装起来。
1 template<class T, class U>
2 class Conversion
3 {
4 typedef char Small;
5 class Big {char dummy[2];};
6 static Small Test(U);
7 static Big Test();
8 static T MakeT();
9 public:
10 // T可以转换为U
11 enum {exists = sizeof(Test(MakeT())) == sizeof(Small)};
12 // 可以双向转换
13 enum {exists2Way = exists && conversion<U, T>::exists };
14 enum {sameType = false};
15 };
16 //利用偏特化处理 sameType == true 情况
17 template<class T>
18 class Conversion<T, T>
19 {
20 public:
21 enum { exists = 1, exists2Way = 1, sameType = 1};
22 };
最后,我们可以根据这个来判断两个类之间是否有继承关系:
1 #define SUPER_SUB_CLASS(T, U)\
2 (Conversion<const U*, const T*>::exists &&\
3 !Conversion<const T*, const void*>::sameType)
如果U是共有继承于T,或者T和U是同一型别,SUPER_SUB_CLASS(T,
U)都传回true。这里加上const饰词的原因是,我们不希望因const而导致转换失败,对一个型别const两次,第二个const会被忽略。