【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法 (2)

(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);//这里传入的是一个迭代器(原生指针也是一种迭代器) }

【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法


上面的做法呢,通过多层的迭代,很巧妙地导出了 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 }

【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

上面的解决方案看着可行,但其实呢,实际上还是有问题,这里有一个隐晦的陷阱:实际上并不是所有的迭代器都是 class type ,原生指针也是一种迭代器,由于原生指针不是 class type ,所以没法为它定义内嵌型别

【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

因为 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 为“原生指针”的情况,是泛化版本的限制版

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspdfd.html