C++ Template 基础篇(二):类模板
2017-02-26 15:57
330 查看
Template 基础篇-类模板
Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第二部分。Template 基础篇-类模板
类模板定义
类模板
类模板中的成员函数模板
类模板Tips
类模板中的static成员
类模板成员函数实例化
类模板别名
特化与偏特化
类模板的特化与偏特化
类模板成员特化
类模板定义
类模板也是公共逻辑的抽象,通常用来作为容器(例如:vector)或者行为(例如:clonable)的封装。类模板
下面定义了一个Printer类模板,负责打印以及转化为string。template<typename T> class Printer { public: explicit Printer(const T& param):t(param){} string&& to_string(); //定义在内部 void print() { cout << t << endl; } private: T t; }; //定义在外部 template<typename T> string&& Printer<T>::to_string() { strstream ss; ss << t; return std::move(string(ss.str())); } Printer p(1); //error Printer<int> p(1); //ok
与函数模板不同,类模板不能推断实例化。所以你只能显示指定类型参数使用
Printer<int> p(1),而不能让编译器自行推断
Printer p(1)。
类模板的成员函数既可以定义在内部,也可以定义在外部。定义在内部的被隐式声明为inline,定义在外部的类名之前必须加上template的相关声明。
类模板中的成员函数模板
我们还可以把类模板和函数模板结合起来,定义一个含有成员函数模板的类模板。template<typename T> class Printer { public: explicit Printer(const T& param):t(param){} //成员函数模板 template<typename U> void add_and_print(const U& u); private: T t; }; //注意这里要有两层template的说明 template<typename T> template<typename U> void Printer<T>::add_and_print(const U& u) { cout << t + u << endl; } Printer<int> p(42); p.add_and_print(1.1); //自动推断U为double,打印出43.1
类模板Tips
类模板中的static成员
类模板中可以声明static成员,在类外定义的时候要增加template相关的关键词。另外,需要注意的是:每个不同的模板实例都会有一个独有的static成员对象。template<typename T> class Printer { public: explicit Printer(const T& param):t(param){} static int s_value; private: T t; }; template<typename T> //注意这里的定义方式 int Printer<T>::s_value = 1; Printer<int> pi(1); Printer<int> pi2(1); Printer<double> pd(1.0); pi.s_value += 1; //pi和pi2中的改变了,pd的没改变
其实这个结论是显然的,static成员属于实例化后的类,不同的实例化当然有不同static成员。就像上面的例子一样,
pi.s_value += 1只影响到了
Printer<int>,而不会影响到
Printer<double>。
函数模板中的static局部变量也有类似的工作方式。
类模板成员函数实例化
为了节省资源,类模板实例化时并不是每个成员函数都实例化了,而是使用到了哪个成员函数,那个成员函数才实例化。template<typename T> class Printer { public: explicit Printer(const T& param):t(param){} void print() { cout << t << endl; } private: T t; }; class empty{}; empty e; Printer<empty> p(e); //ok
虽然成员函数print无法通过编译,但是因为没有使用到,也就没有实例化print,所以没有触发编译错误。
类模板别名
为了简化代码,我们可以使用typedef为类模板的某个实例定义一个别名,也可以使用using语句固定一个或多个类型参数(这有点偏特化的意思了)。typedef std::pair<int, int> PairOfInt; //ok,为std::pair<int, int>定义了一个别名 template <typename T> using WithNum = std::pair<T, int>; //ok,相当于定义了一个std::pair的偏特化 PairOfInt poi; //实际类型,std::pair<int, int> WithNum<std::string> strs; //实际类型,std::pair<string, int> WithNum<int> ints; //实际类型,std::pair<int, int>
特化与偏特化
类模板的特化与偏特化
就像函数模板重载那样,你可以通过特化(偏特化)类模板来为特定的类型指定你想要的行为。类模板的特化(偏特化)只需要模板名称相同并且特化列表<>中的参数个数与原始模板对应上即可,模板参数列表不必与原始模板相同模板名称相同。一个类模板可以有多个特化,与函数模板相同,编译器会自动实例化那个最特殊的版本。template<typename T> //基本模板 class S { public: void info() { printf("In base template\n"); } }; template<> //特化 class S<int> { public: void info() { printf("In int specialization\n"); } }; template<typename T> //偏特化 class S<T*> { public: void info() { printf("In pointer specialization\n"); } }; template<typename T, typename U> //另外一个偏特化 class S<T(U)> { public: void info() { printf("In function specialization\n"); } }; int func(int i) { return 2 * i; } S<float> s1; s1.info(); //调用base模板 S<int> s2; s2.info(); //调用int特化版本 S<float*> s3; s3.info(); //调用T*特化版本 S<decltype(func)> s4; s4.info(); //调用函数特化版本
提供了所有类型实参的特化是完全特化,只提供了部分类型实参或者T的类型受限(例如:T*)的特化被认为是不完整的,所以也被称为偏特化。完全特化的结果是一个实际的class,而偏特化的结果是另外一个同名的模板。
类模板成员特化
除了可以特化类模板之外,还可以对类模板中的成员函数和普通静态成员变量进行特化。template<typename T> class S { public: void info() { printf("In base template\n"); } static int code; }; template<typename T> int S<T>::code = 10; template<> int S<int>::code = 100; //普通静态成员变量的int特化 template<> void S<int>::info() { //成员函数的int特化 printf("In int specialization\n"); } S<float> s1; s1.info(); //普通版本 printf("Code is: %d\n", s1.code); //code = 10 S<int> s2; s2.info(); //int特化版本 printf("Code is: %d\n", s2.code); //code = 100
相关文章推荐
- C++基础:C++模板(Template)简介
- [c++][template]模板基础知识
- C++ template —— 深入模板基础(二)
- C++基础:C++模板(Template)简介
- C++基础::变量模板(variable template)
- c++ template笔记(3)非类型模板参数nontype template parameters
- 转@关于c++模板template中的typename 和class的区别
- C++之模板(Template)
- c++模板中的 typename 和 template 关键字用法
- C++ Template----类模板简单阐述
- 【C++模板】特化与偏特化 template [partial] specialization
- <C++实践系列>C++中的模板(template)
- C++之模板(Template)
- 【C++模板】特化与偏特化 template [partial] specialization
- C++_函数模板基础知识
- C++_类模板基础知识
- C++模板引擎Ctemplate的介绍
- C++ 模板(template)(泛型)入门例子
- c++ template - 成员模板
- C++中的模板(template)