模版
定义
模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现了真正的代码可重用性。 模版可以分为两类,一个是函数模版,另外一个是类模版。
C++的模板机制被证明是图灵完备的,即可以通过模板元编程(template meta programming)的方式在编译期做任何计算。
实例化
模板定义本身不参与编译,而是编译器根据模板的用户使用模板时提供的类型参数生成代码,再进行编译。 用户提供不同的类型参数,就会实例化出不同的代码。
类模版
类模板描述了一组相关的类或数据类型,它们只能通过类型来区分:整数值、指向(或引用)具有全局链接的变量的指针、其他的组合。 类模板尤其适用于描述通用但类型安全的数据结构。
1 | template <类型形式参数> |
全特化
所谓模板全特化限定死模板实现的具体类型;
1 | template <> |
偏特化
偏特化是指提供另一份template定义式,而其本身仍为templatized,这是针对于template参数更进一步的条件限制所设计出来的一个特化版本。 也就是如果这个模板有多个类型,那么只限定其中的一部分;
1 | template <class T2> |
函数模版
1 | template <类型形式参数> //类型形式参数即此格式:<typename 形式参数> 或 <class 形式参数> |
全特化
函数模板全特化和类模板全特化本质是一样的,是对模板参数的特殊化处理。
1 | template <> |
特化的歧义
1 | template <class T> |
此时编译器不知道f()是从f\()特化来的,编译时会有错误:
1 | error: no function template matches function template specialization 'f' |
这时我们便需要显式指定”模板实参”:
1 | template <class T> |
偏特化
函数模版没有偏特化。
例如下面代码会编译出错:
1 | template <class T1, class T2> |
但函数允许重载,声明另一个函数模板即可替代偏特化的需要:
1 | template <class T2> |
多数情况下函数模板重载就可以完成函数偏特化的需要,一个例外便是std命名空间。 std是一个特殊的命名空间,用户可以特化其中的模板,但不允许添加模板(其实任何内容都是禁止添加的)。 因此在std中添加重载函数是不允许的,在Effective C++: Item 25中给出了一个更详细的案例。
总结
- 函数模板只有全特化,没有偏特化;
- 模板、模板的特化和模板的偏特化都存在的情况下,编译器在编译阶段进行匹配,优先特殊的;
- 模板函数不能是虚函数;因为每个包含虚函数的类具有一个virtual table,包含该类的所有虚函数的地址,因此vtable的大小是确定的。模板只有被使用时才会被实例化,将其声明为虚函数会使vtable的大小不确定。所以,成员函数模板不能为虚函数。
本文作者:jujimeizuo
本文地址: https://blog.jujimeizuo.cn/2023/01/11/c-template-specialization/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!