本书从概念和设计上讲述了泛型编程。个人认为只需要阅读前面九章即可(实际上我只读了前面七章),后面章节是一些算法和API的讲述,可以在用到的时候再来查阅。
全书N次提到concept,model以及refinement这几个概念。
Concept是指一组具有某种相同特性的类型。比如Input Iterator,可以通过它来读取容器的元素,也可以对它进行加一操作;这样的Input Iterator多了去了,char*、标准STL的很多迭代器,都符合Input Iterator的特征。每一个这样的迭代器类型,我们都称之为Input Iterator的一个model。
“如果一个concept C2提供了concept C1的所有功能,再加上了其他额外功能,我们就说C2是C1的一个refinement”。比如Random Access Iterator是Input Iterator的一个refinement。初看起来,refinement有点类似于继承。事实上它们的确很类似,我的理解是:如果类型T2继承于T1,那么T2的所有对象(object)也都是T1的对象。类似地,如果C2是C1的refinement,那么C2的每个类型(model)必然也是C1的类型。
Refinement描述的是两个concept之间的关系,而继承描述的是两个类型之间的关系。好吧,不需要太纠结于此了。
之前看了《Effective STL》,里面涉及到ptr_func, mem_func, mem_fun_ref等,看的时候对这几个东西不甚了解,现在觉得其实应该先看一些泛型编程的书,再去看《EffectiveSTL》比较好。比如说为什么不能对函数指针直接加上not1适配器,这是因为not1需要接收一个函数对象作为参数,这时候就需要用到ptr_func,代码如下:
仅仅是对函数指针多包了一层而已。咋一看,其实实现代码也很简单。至于not1的实现,如下:
class unary_negate:
Function not1:
看了这些代码,对not1(ptr_func(funcPointer))这类东西也就好理解一些。
以下代码有什么问题?
int A[5] = {1, 2, 3, 4, 5};
vector<int>vec;
copy(A, A + 5, vec.begin());
程序会崩溃。因为vec是空的,对vec.begin()解引用必死无疑。
解决方法有很多,其中一种如下:
int A[5] = {1, 2, 3, 4, 5};
vector<int>vec;
copy(A, A + 5, back_inserter(vec));
back_inserter到底干了什么,且看:
// 先构造一个back_insert_iterator<Vector>
template<class _Container> inline
back_insert_iterator<_Container>back_inserter(_Container& _Cont)
{ // return a back_insert_iterator
return(std::back_insert_iterator<_Container>(_Cont));
}
再看:
// 对back_insert_iterator进行解引用
back_insert_iterator<_Container>&operator*()
{ // pretend to return designated value
return(*this);
}
// 赋值操作,实际就是对vec进行push_back
back_insert_iterator<_Container>&operator=(
typename _Container::const_reference_Val)
{ //push value into container
container->push_back(_Val);
return (*this);
}
所以,加上back_inserter之后,程序不会再崩溃。
以上就是对本书的一点感悟。