除了可以计算数值,编译期更具有价值的是类型计算。我们可以将编译期常量和类型都看做是编译期的可计算对象。
我们知道模板的所有形参被实参替换后,模板自身就具现化为一个具体的类型了。但是模板自身具现化的这个类型对于我们想要的编译期类型计算来说缺少抽象能力。模板的类型计算结果如果保存在模板内部定义的嵌套类型中,这将会为模板计算提供封装性和信息隐藏的能力。
模板内部定义类型的方法除了可以直接在模板内部定义嵌套类,更多的是使用typedef。
如下我们定义了一个类模板,它的入参是类型T,内部通过Type定义了T的指针类型T*
。
template<typename T>
struct PointerOf
{
typedef T* Type;
};
我们可以像下面这样使用该模板:
PointerOf<const char>::Type s = "Hello world!";
std::cout << s << std::endl;
如同前面数值计算一样,我们可以这样理解PointerOf
:PointerOf
是一个编译期的函数,它使用<typename T>
声明了它有一个类型形参T。我们通过访问Type
可以获得该函数的返回值,它也是一个类型。这个函数的功能是在C++编译期将一个输入类型转变为它对应的指针类型。所以调用PointerOf<const char>::Type
其实是和const char *
本质上一样。
我们定义的这个PointerOf
似乎有些无聊,但这却是类型计算的基础。后面当我们把这种类型计算的小函数组合起来,会逐渐看到它们的威力。
最后,C++11标准扩展了using关键字来专门定义类型别名,它的用法和定义变量的习惯类似,且功能也比typedef强大得多,所以我们后续类型计算统一用using关键字定义类型别名。PointerOf
的定义修改如下:
template<typename T>
struct PointerOf
{
using Type = T*;
};