C++ Primer第五版之第16章 模板与泛型编程

第16章 模板与泛型编程

定义模板

函数模板

  • 模板定义以关键字template开始,后跟一个模板参数列表(是一个逗号分隔的一个或多个模板参数的列表),用<>包围起来。
  • 在模板定义中,模板参数列表不能为空。
template <typename T>
int compare(const T &v1, const T &v2)
{
    if (v1 < v2)   return -1;
    if (v2 < v1)   return 1;
    return 0;
}
  • 实例化函数模板:调用template时,编译器使用实参的类型来确定绑定到模板参数T的类型,之后编译器利用推断出来的模板参数来实例化一个特定版本的函数。
  •  模板类型参数:使用关键字class或typename来指定模板类型参数(常使用typename)。
template<typename T, class U>
calc(const T&, const U&);
  • 非类型参数:表示一个值而非一个类型,通过一个特定的类型名而非关键字class或typename来指定
    • 当一个模板被实例化时,非类型参数被一个用户提供的或编译器推断出来的值所代替,这些值必须是常量表达式。
    • 非类型模板参数的模板实参必须是常量表达式.
template <unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M])
{
    return strcmp(p1,p2);
}
compare("Hi", "Mom");
  • 函数模板可以声明为inline或constexpr的,inline或constexpr说明符放在模板参数列表之后,返回类型之前
  • 模板编译:当我们实例化出模板的一个特定版本时,编译器才会生成代码; 函数模板和类模板成员函数的定义通常放在头文件中。

类模板

  •  用来生成类的蓝图,与函数模板不同之处在于编译器不能为类模板推断模板参数类型,而需要显式提供参数类型。
template<typename T>
class Blob {
public:
    //...
private:
    std::shared_ptr<std::vector<T>> data;
};
Blob<int> ia;
  • 当使用一个类模板时,必须提供额外信息,这些额外信息是显示模板实参列表,它们被绑定到模板参数,编译器使用这些模板实参来实例化出特定的类。
  • 一个类模板的每个实例都形成一个独立的类。实例化出来的Blob<int>与其他的Blob类型都没有关联,也不会对任何其他Blob类型的成员有特殊访问权限
  • 一个类模板中的代码如果使用了另外一个模板,通常不将一个实例类型的名字用作其模板实参,相反将模板自己的参数当作被使用模板的实参。
//在模板作用于中引用模板类型
std::shared_ptr<vector<T>> data;    //T为Blob模板的参数
  • 在类外定义一个成员函数时,必须以关键字template开始,后接类模板参数列表;另外还必须说明成员属于哪个类。
template <typename T>
void Blob<T>::check(size_type i, const string &msg) const
{
    if (i >= data->size())
        throw out_of_range(msg);
}
template<typename T>
T& Blob<T>::operator[](size_t i){
	check(i, "subscript out of range"); //检查下标
	return(*data)[i];
}
  • 默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。
  • 当我们使用一个类模板类型时必须提供模板实参,但在类模板自己的作用域中我们可以直接使用模板名而不提供实参。
  • 当我们在类模板外定一起成员时,必须记住我们只有在遇到类名时才表示进入类的作用域。
template<typename T>
BlobPtr<T> BlobPtr<T>::operator++(int);

类模板和友元

  • 如果类模板包含一个非模板友元,则友元被授权可以访问所有模板实例;如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定实例。
  • 进行友元声明必须首先前置声明模板本身。
//前置声明,在Blob中声明友元所需
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T>
    bool operator==(const Blob<T>&, const Blob<T>&);

template <typename T> class Blob {
        //每个Blob实例将访问权限授予用相同类型实例化的BlobPtr和相等运算符
        friend class BlobPtr<T>;
        friend bool operator==<T>
                (const Blob<T>&, const Blob<T>&);
};
  • 可以定义typedef来引用实例化的类,还可以使用using来声明类型别名。
typedef Blob<string> StrBlob;    //引用实例化的Blob类

template <typename T> using twin = pair<T, T>;   //twin为pair<T, T>的别名
twin<string> authors;     //authors是一个pair<string, string>

类模板的static成员

  • 每一个类模版的实例都有自己的static成员实例,但对于给定的类型,该static成员实例共享;类模版的static成员有且仅有一个定义。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值