本章介绍许多在本书中要用到的高级技术。
1. 编译器Assertion.
不同于以往的运行期的Assert. 这个Assertion是用来判断那些可以在编译器确定的关系, 比如类型转换, sizeof等。 利用一个模版类, 在模版参数为true时,给出实现,而false时,不给出实现。 那么当STATIC_CHECK的参数为false, 就不能生成相应的函数。(因为没有实现), 最后还作了一些辅助工作, 以让编译器输出错误的原因。
2. 模版偏特化(Partial Template Specialization)
这个概念在模板中也属于比较晦涩的, 而大多数模版技巧都要用到这个特性,所以给了专门的叙述。有一点比较重要: 函数不能偏特化,只能全特化, 如果要达到偏特化的效果,只能巧妙的运用函数重载机制。
3. 局部类
函数内部可以定义的类, 可以提高类的域的概念,并不是非有不可的东西。
4. Int2Type
用不同的数值来生成不同的类型, 如:
template<int v>
struct Int2Type
{
enum {value = v};
}
用这个概念可以根据不同的int值来调用不同的函数特化实现, 实现分发的目的。
5. Type2Type
用函数重载来模拟部分的函数偏特化类似行为。(因为函数偏特化是不行的).如:
template<typename T>
struct Type2Type
{
typedef T OriginType;
}
template<class T, class U>
T* Create(const U& arg, Type2Type<T>)
{
return new T(arg);
}
template<class U>
Widget* Create(const U& arg, Type2Type<Widget>)
{
return new Widget(arg, -1);
}
String *pStr = Create("Hello", Type2Type<String>());
Widget* pW = Create(100, Type2Type<Widget>());
6. 类型选择
用一个select类模版来实现, 通过bool值选择不同的类型。 就好像? : 操作符一样。除了选择的是类型之外。
如 Select<isPolymorphic, T*, T>::Result.
这个表达式,根据isPolymorphic来选择类型, 如果true, 则选择T*, 如果false, 则选择T.
7. 编译期间确定不同类型之间的关系(可转换, 继承)
利用了sizeof在编译期间可以知道类型细节的特点来实现。实现:
Small Test(U);
Big Test(...);
Small和Big是sizeof(Small) != sizeof(Big)的两个类型。 如果想知道T是否可以转换为U, 则执行
sizeof(Test(T)) == sizeof(Small). 如果相等, 则可转换。
原因为: 如果T可以转换为U, 则会调用Small Test(U)这个函数. 否则会调用Big Test(...). 返回两个不同大小的类型, 根据这两个类型的大小,就可以知道是否可以转换了。
8. typ_info wrapper
type_info是运行期得到对象类型的一个函数,这个函数有些比较繁琐的细节,本节将其封装。
9. NullType, EmptyType
两个占位符。
10. Type Traits
根据传入的Type, 得到Type的各种形态。 如:PointeeType, referencedType. NonConstType等。 也可以判断一些类型的特征,比如是否为指针,是否为unsignedInt等。 用到了第三章的typelist的一些实现。