(2) 对于 list ,取下一个元素不是通过自增而是通过 next 指针来取,使用智能指针可以对自增进行重载,从而提供统一接口。
3、template 参数推导参数推导能帮我们解决什么问题呢?
在算法中,你可能会定义一个简单的中间变量或者设定算法的返回变量类型,这时候,你可能会遇到这样的问题,假如你需要知道迭代器所指元素的类型是什么,进而获取这个迭代器操作的算法的返回类型,但是问题是 C++ 没有 typeof 这类判断类型的函数,也无法直接获取,那该如何是好?
注意是类型,不是迭代器的值,虽然 C++ 提供了一个 typeid() 操作符,这个操作符只能获得型别的名称,但不能用来声明变量。要想获得迭代器型别,这个时候又该如何是好呢?
function template 的参数推导机制是一个不错的方法。
例如:
如果 I 是某个指向特定对象的指针,那么在 func 中需要指针所指向对象的型别的时候,怎么办呢?这个还比较容易,模板的参数推导机制可以完成任务,
template <class I> inline void func(I iter) { func_imp(iter, *iter); // 传入 iter 和 iter 所指的值,class 自动推导 }通过模板的推导机制,就能轻而易举的获得指针所指向的对象的类型。
template <class I, class T> void func_imp(I iter, T t) { T tmp; // 这里就是迭代器所指物的类别 // ... 功能实现 } int main() { int i; func(&i);//这里传入的是一个迭代器(原生指针也是一种迭代器) }上面的做法呢,通过多层的迭代,很巧妙地导出了 T ,但是却很有局限性,比如,我希望 func() 返回迭代器的 value type 类型返回值, 函数的 "template 参数推导机制" 推导的只是参数,无法推导函数的返回值类型。万一需要推导函数的返回值,好像就不行了,那么又该如何是好?
这就引出了下面的内嵌型别。
4、声明内嵌型别上述所说的 迭代器所指对象的型别,称之为迭代器的 value type 。
尽管在 func_impl 中我们可以把 T 作为函数的返回值,但是问题是用户需要调用的是 func 。
如果在参数推导机制上加上内嵌型别 (typedef) 呢?为指定的对象类型定义一个别名,然后直接获取,这样来看一下实现:
template<typename T> class MyIter { public: typedef T value_type; //内嵌类型声明 MyIter(T *p = 0) : m_ptr(p) {} T& operator*() const { return *m_ptr;} private: T *m_ptr; }; //以迭代器所指对象的类型作为返回类型 //注意typename是必须的,它告诉编译器这是一个类型 template<typename MyIter> typename MyIter::value_type Func(MyIter iter) { return *iter; } int main(int argc, const char *argv[]) { MyIter<int> iter(new int(666)); std::cout<<Func(iter)<<std::endl; //print=> 666 }上面的解决方案看着可行,但其实呢,实际上还是有问题,这里有一个隐晦的陷阱:实际上并不是所有的迭代器都是 class type ,原生指针也是一种迭代器,由于原生指针不是 class type ,所以没法为它定义内嵌型别。
因为 func 如果是一个泛型算法,那么它也绝对要接受一个原生指针作为迭代器,下面的代码编译没法通过:
int *p = new int(5); cout<<Func(p)<<endl; // error要解决这个问题,Partial specialization (模板偏特化)就出场了。
5、Partial specialization(模板偏特化)所谓偏特化是指如果一个 class template 拥有一个以上的 template 参数,我们可以针对其中某个(或多个,但不是全部)template 参数进行特化,比如下面这个例子:
template <typename T> class C {...}; //此泛化版本的 T 可以是任何类型 template <typename T> class C<T*> {...}; //特化版本,仅仅适用于 T 为“原生指针”的情况,是泛化版本的限制版