首页 c++Prime NO16
文章
取消

c++Prime NO16

第16章 模板与泛型编程

16.1 定义模板

假如要编写函数比较两个类型的值,实际要为每个类型编写

16.1.1 函数模板

模板定义以关键字 template 开始,后跟一个模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用<>包围 模板参数列表不能为空

实例化函数模板

当调用一个函数模板时,编译器通常用函数实参来为我们推断模板实参。 即,调用compare时,根据实参类型推断T为intasdf

1
2
3
4
5
6
7
8
template <typename T>
int compare(const T &v1,const T &v2)
{
    if (v1 < v2) return -1;
    if (v1 > v2) return 1;
    return 0;
}   
cout << compare(1,0) << endl;

编译器生成的版本通常被称为模板的实例

模板类型参数

1
2
3
4
5
6
7
8
template <typename T>
T foo(T* p)
{
    T tmp = *p;
    return tmp;
}
template <typename T,class U>....
typenameclass含义相同,可以交换使用。

非类型模板参数

一个非类型参数表示一个值而非一个类型。 当一个模板被实例化,非类型参数被编译器推断出的值所代替。 例如: 第一个模板参数表示第一个数组的长度,第二个表示第二个数组长度

1
2
3
4
5
6
7
template<unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p1)[M])
{
    returen strcmp(p1,p2);
}
compare("hi","mom");
编译器实例化NM

非类型模板参数的模板实参必须时常量表达式

inline和constexpr的函数模板

inline和constexpr放在模板参数列表之后,返回类型之前:

编写类型无关的代码

模板程序应该尽量减少对实参类型的要求。

模板编译

当编译器遇到一个模板定义时,它并不生成代码,只有我们实例化出模板的一个特定版本时,编译器才会生成代码。

函数模板和类模板成员函数的定义通常放在头文件中

类定义和函数声明放在头文件中,而普通函数和类的成员函数的定义放在源文件中

16.1.2 类模板

定义类模板

实例化类模板

显式模板实参 Blob ia;

一个类模板的每个实例都形成一个对立的类。

在模板作用域中引用模板类型

类模板和友元

为了引用(类或者函数)模板的一个特定实例,必须首先声明模板本身

1
template <typename> class BlobPtr;//声明

通用和特定的模板友好关系

一个类也可以将另一个模板的每个实例都声明为自己的友元,或者限定特定的实例为友元。 为了让所有实例成为友元,友元声明中必须使用与类模板本身不同的模板参数

令模板自己的类型参数成为友元

1
2
3
4
5
6
新标准中:
template <typename Type> class Bar{
friend Type;//将访问权限授予用来实例化Bar的类型
};
对于类型Foo
Foo将成为Bar<Foo> 的友元

模板类型别名

可以 **typedef Blob StrBlob;** 新标准允许为类模板定义一个类型别名:

1
2
template<typename T> using twin = pair<T,T>;
twin<string> authors;//authors是一个pair<string,string>

类模板的static成员

类模板可以声明static成员

1
2
3
4
5
6
template <typename T> class Foo{
    public:
    static size_t count(){return ctr;}
    private:
    static size_t ctr;
};

Foo<x>都有一个ctr和count成员,也即都共享相同的ctr对象和count函数。 类模板的每个实例都有一个独有的static对象 一个static成员只有在使用时才会实例化

16.1.3 模板参数

模板参数与作用域

模板参数会隐藏外层作用域中声明的相同名字。

模板声明

模板声明必须包含模板参数

与函数参数相同,声明中的模板参数的名字不必与定义中相同

使用类的类型成员

默认情况下,cpp成员假定通过作用运算符访问的名字不是类型。因此我们希望使用一个模板类型参数的类型成员,就必须显式告诉编译器该名字是一个类型。 template <typename T> typename T::value_type top(const T& c)

当我们希望通知编译器一个名字表示类型时,必须使用关键字typename,而不能使用class.

默认模板实参

模板默认实参与类模板

16.1.4 成员模板

一个类(无论是普通类还是类模板)可以包含本身时模板的成员函数 这种成员被称为成员模板不能是虚函数

普通(非模板)类的成员模板

类模板的成员模板

实例化与成员模板

16.1.5 控制实例化

当模板被使用时才会实例化,意味着相同的实例可能出现在多个对象文件中 当两个或多个独立编译的源文件使用了相同的模板,并提供了相同的模板参数时,每个文件中都会有该模板的一个实例。 大系统中,多个文件中实例化相同模板的额外开销很严重。 新标准中,可以通过显式实例化在避免 有以下形式:

1
2
extern template declaration;//实例化声明
template declaration;//实例化定义

declaration 是一个类或者函数声明,其中所有模板参数已经被替换为模板实参

实例化定义会实例化所有成员

在一个类模板的实例化定义中,所用类型必须能用于模板的所有成员函数

16.1.6 效率与灵活性

shared_ptr和unique_ptr之间明显不同是它们所保存的指针的策略 前者给予我们共享指针所有权的能力 后者则独占指针 前者可以重载产出其 后者必须在定义unique_ptr时以显式模板实参的形式提供删除器的类型。

在运行时绑定删除器

删除器必须保存为一个指针或一个封装了指针的类

本文由作者按照 CC BY 4.0 进行授权
热门标签
文章内容
热门标签