曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 3463|回复: 0
打印 上一主题 下一主题

模板的具体化

[复制链接]

716

主题

734

帖子

2946

积分

超级版主

Rank: 9Rank: 9Rank: 9

积分
2946
跳转到指定楼层
楼主
发表于 2013-12-17 00:11:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
类模板与函数模板类似,可以有隐式实例化、显式实例化和显式具体化,这些统称为具体化(specialization)

1. 隐式实例化(implicit instantiation)
隐式实例化,即声明一个或多个对象,并指出所需的类型,而编译器使用通用模板来生成具体的类定义:
  1. ArrayTP<int, 100> stuff;  // 隐式实例化
复制代码
编译器在需要对象之前,不会生成类的隐式实例化:
ArrayTP<double, 30> *pt;     // 声明一个类指针,但目前还不需要任何对象
pt = new ArrayTP<double, 30>;        // 现在,需要一个对象了

第 2 条语句导致编译器生成类定义,并根据该定义创建一个对象。

2. 显式实例化(explicit instantiation)
当使用关键字 template 并指出所需类型来声明类时,编译器将生成类声明的显式实例化。声明必须位于模板定义所在的名称空间中。下面的声明将 ArrayTP<string, 100> 声明为一个类:
  1. template class ArrayTP<string, 100>;    //生成一个 ArrayTP<string, 100> 类
复制代码
在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。

3. 显式具体化(explicit specialization)
显示具体化是特定类型(用于替换模板中的泛型)的定义。有时候,可能需要在为特殊类型实例化时,对模板进行修改,使其行为不同。在这种情况下,可以创建显示具体化。例如,假设已经为用于表示排序后数组的类(元素在加入时被排序)定义了一个模板:
  1. template <typename T>
  2. class SortedArray
  3. {
  4.    ...// 省略细节
  5. };
复制代码
另外,假设模板使用了 > 运算符来对值进行比较。对于数字的比较,> 运算符是适用的。但如果 T 是 const char * 表示的字符串,这就不适用了。实际上,模板倒还是可以正常工作的,但字符串是按照其地址(十六进制地址字母排序),这可能不符合你的要求。在这种情况下,类定义应该使用 strcmp() 函数,而不是 > 来比较了。为此,我们可以提供一个显式模板具体化,这将采用为具体类型(这里是 const char *)定义的模板,而不是为泛型定义的模板。如果具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本。

具体化类模板定义格式如下
template <> class classname<specialized-type-name> { ... };

早期的编译器可能不能识别 template <> ,而只能识别将其省略的版本。

要使用新的表示法提供一个专供于 const char * 类型使用的 SortedArray 模板,可以使用类似于下面的代码:
  1. template <> class SortedArray<const char *>
  2. {
  3.    ...// 省略细节
  4. }
复制代码
其中的实现代码使用的是 strcmp() 而不是 > 来比较数组值。现在,当请求 const char * 类型的 SortedArray 模板时,编译器将使用上述专用的定义,而不是通用模板。

4. 部分具体化 (partial specialization)
C++ 还允许部分具体化,即部分闲置模板的通用性。例如,可以给类型参数之一指定具体的类型:
// 通用模板
template <class T1, class T2> class Pair { ... };
//将 T2 具体化为 int
template <class T1> class Pair<T1, int> { ... };

关键字 template 后满的 <> 声明的是没有被具体化的类型参数。因此,上述第二个声明将 T2 具体化为 int,但 T1 保持不变。注意,如果指定所有的类型,则 <> 内将为空,这将导致显式具体化:
// 将 T1 和 T2 具体化为 int
template <> class Pair<int, int> { ... };

如果有多个模板可供选择,编译器将使用具体化程度最高的模板。那么对于上述的 3 个模板,我们有:
Pair<double, double> p1;   // 使用通用的 Pair 模板
Pair<double, int> p2;                      // 使用 Pair<T1, int> 部分具体化模板
Pair<int, int> p3;                            //  使用 Pair<int, int> 显式具体化模板


也可以通过为指针提供特殊版本来部分具体化现有的模板:
template<class T>  // 通用模板
class Feeb { ... };

template<class T *>          // 针对指针的部分具体化
class Feeb { ... };               // 针对通用模板里的代码做相应修改


如果提供的类型不是指针,如 Feeb<char> fb1;  ,那么编译器使用通用模板。
如果提供的类型是指针,如 Feeb<char *> fb2; ,那么编译器使用指针具体化版本。

部分具体化特性使得能够设置多种限制。例如有:
// 通用模板
template <class T1, class T2, class T3> class Trio{...};
// 将 T3 部分具体化为 T2
template <class T1, class T2> class Trio<T1, T2, T2> {...};
// 将 T2 和 T3 部分具体化为 T
template <class T1> class Trio<T1, T1*, T1*> {...};

对于上述声明,编译器将作出如下选择:
Trio<int, short, char *> t1;    // 使用通用模板
Trio<int, short> t2;   // 使用 Trio<T1, T2, T2>
Trio<char, char *, char *> t3;   //使用 Trio<T1, T1*, T1*>


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-4-30 09:55 , Processed in 0.077837 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表