Skip to content

Latest commit

 

History

History

16章

C++ Primer 第十六章:模板与泛型编程


Exercise 16,1

给出实例化的定义。

用模板生成的classfunction

Exercise 16.2

编写并测试你自己版本的compare函数。

template <typename T> int compare(const T &v1, const T &v2)
{
	if (v1 < v2) return -1;
	if (v2 < v1) return 1;
	else return 0;
}

Exercise 16.3

对两个Sales_data对象调用你的compare函数,观察编译器在实例化过程中如何处理错误。

error C2678: binary '<': no operator found which takes a left-hand operand of type 'const Sales_data' (or there is no acceptable conversion)

Exercise 16.4

编写行为类似标准库find算法的模板。函数需要两个模板类型参数,一个表示函数的迭代器参数,另一个表示值的类型,使用你的函数在一个vector<int>和一个list<string>中查找给定值。

see Find

Exercise 16.5

为6.2.4节(第195页)中的print函数编写模板版本,它接受一个数组的引用,能处理任意大小、任意元素类型的数组。

see Print

Exercise 16.6

你认为接受一个数组实参的标准库函数beginend是如何工作的?定义你自己版本的beginend

see Begin&End

Exercise 16.7

编写一个constexpr模板,返回给定数组的大小。

see sizeOfArray

Exercise 16.8

在第97页的“关键概念”中,我们注意到,C++程序员喜欢使用!=而不喜欢<。解释这个习惯的原因。

因为大多数迭代器都有==!=运算符,而没有<运算符,使用!=就不必担心我们正在处理的容器的精确类型。

Exercise 16.9

什么是函数模板?什么是类模板?

  • 函数模板: 一个函数模板就是一个公式,可用来生成针对特定类型的函数版本。
  • 类模板:类模板是用来生成类的蓝图的。
  • 区别:编译器不能为类模板推断模板参数的类型。

Exercise 16.10

当一个类模板被实例化时,会发生什么?

编译器将重写类模板,通过给定的模板参数替换模板参数T的每个实例。

Exercise 16.11

下面的List定义是错误的。应如何修正它?

template <typename elemType> class ListItem;
template <typename elemType> class List {
public:
  List<elemType>();
  List<elemType>(const List<elemType> &);
  List<elemType>& operator=(const List<elemType> &);
  ~List();
  void insert(ListItem *ptr, elemType value);
private:
  ListItem *front, *end;
};

实验类模板ListItem时需要模板参数

void insert(ListItem<elemType> *ptr, elemType value);
ListItem<elemType> *front, *end;

Exercise 16.12

编写你自己版本的BlobBlobPtr模板,包含书中未定义的多个const成员。

see cpp | hpp | test 这里在编译的时候,出现无法解析的外部符号,解决方法戳这里。我使用第一种方案解决问题。

Exercise 16.13

解释你为BlobPtr的相等和关系运算符选择哪种类型的友好关系?

对于每个BlobPtr的实例,如果具有相同的类型,则为友好关系。

Exercise 16.14

编写Screen类模板,用非类型参数定义Screen的高和宽。

see hpp | cpp

Exercise 16.15

为你的Screen模板实现输入和输出运算符,Screen类需要哪些友元(如果需要的话)来令输入和输出运算符正确工作?解释每个友元声明(如果有的话)为什么是必要的。

Blob是一样的。

Exercise 16.16

StrVec类重写为模板(参见13.5节,第465页),命名为Vec

see hpp | test

Exercise 16.17

声明为typename的类型参数和声明为class的类型参数有什么不同(如果有的话)?什么时候必须使用typename

当我们想通知编译器一个名称代表一个类型时,我们必须使用关键字typename,而不是类。 看到一个比较好的说明http://blog.csdn.net/dick_china/article/details/4522253

Exercise 16.18

解释下面每个函数模板声明并指出它们是否非法。更正你发现的每个错误。

(a) template <typename T, U, typename V> void f1(T, U, V);
(b) template <typename T> T f2(int &T);
(c) inline template <typename T> T foo(T, unsigned int*);
(d) template <typename T> f4(T, T);
(e) typedef char Ctype;
template <typename Ctype> Ctype f5(Ctype a);

更正

(a) template <typename T, typename U, typename V> void f1(T, U, V);
(b) template <typename T> T f2(int &);

Exercise 16.19

编写函数,接受一个容器的引用,打印容器中的元素。使用容器的size_typesize成员来控制打印元素的循环。

see cpp

Exercise 16.20

重写上一题的函数,使用beginend返回的迭代器控制循环。

see cpp