人工智能学习

笔记:STL学习(二)-- 迭代器和traits

本文主要是介绍笔记:STL学习(二)-- 迭代器和traits,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

笔记:STL学习(二)-- 迭代器和traits

迭代器设计思维-STL关键所在

STL设计的中心思想在于:将数据容器和算法设计分开,最后通过迭代器将两者结合起来使用,从技术角度来看并不困难,使用class template和function temlpate就可以达成目标,如何设计初两者之间良好的迭代器,才是最关键的地方。

以算法find()为例

telplate <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value){
    while(first != last && *first != value)
        ++first;
    return value;
}

上述函数是全局范围内的find()函数,与map.find()是不同的,一个是类的成员方法,一个是普通函数。从上述函数,我们还可以发现,无论是何种函数的容器,它的迭代器都支持operate++操作。

(PS:以前一个面试官问我,普通数组可以使用STL的算法吗?答案应该是可以的,因为传入原生指针,上述算法仍然可以顺利执行,不过容器的成员方法就要视情况具体分析了)

迭代器相应型别

在算法使用迭代器的时候,可能会使用到其相应数据类型,比如迭代器所指数据类型,即使使用RTTI性质中的typeid(),也只能获取到类型别名,并不能用来作为变量的声明。

解决办法:利用function template的参数推导(argument deducation)机制。

template <class I, class T>
void func_impl(I iter, T t)
{
    T tmp;     // ...
};
 
 template <class I>
 inline
 void func(I iter)
 {
     func_impl(iter, *iter);
 }
 
 int main()
 {
     int i;
     func(&i);
 }

如上述方法,将func()的工作全部放置在func_impl(),就可以得到类型T了,上述理解就是class I就是迭代器,class T就是迭代器所指数据类型。

Traits编程技巧

上述方法虽然能推导出value type。如果value type用于函数的返回值,上面的方法也就行不通了,毕竟函数的"template参数推导机制"推而导之的只是参数,无法推导函数的返回值。

 template <class T>
 struct MyIter {
     typedef T value_type;
     T* ptr;
     MyIter(T* p=0) : ptr(p){}
     T& operator*() const {retrun *ptr;}
     //...
 };
 
 template <class I>
 typename I::value_type
 func(I ite)
 {  return *ite;  }
 
 //...
 MyIter<int> ite(new int(8));
 cout<< func(ite);

func()的返回型别必须加上关键词typename,因为T是一个template参数,在它被编译器具现化之前,编译器对T一无所悉,换句话说,编译器此时并不知道MyIter<T>::value_type代表的是一个型别或是一个member function或是一个data member。关键词typename的用意在于告诉编译器这是一个型别,才能顺利通过编译。

但并不是所有的迭代器都是class type。原生指针就不是,如果不是class type就无法为其定义内嵌性别。C++采用了template partialspecialization(偏特化)--范围的偏。class template专门用来"萃取"迭代器的特性,而value type正是迭代器的特性之一。

template <class I>
struct iterator_traits{
    typedef typename I::value_type value_type;
};

这个所谓的traits,其意义是,如果I定义有自己的value type,那么通过这个traits的作用,萃取出来的value_type就是I::value_type。换句话说,如果I定义有自己的value type,先前那个func()可以写成这样。

template <class I>
typename iterator_traits<I>::value_type
func(I ite)
{  return *ite;  }

对于原生指针,如int*,就不是一种class type,通过偏特化的方式,可以解决这个问题。

template <class T>
struct iterator_traits<T*>{
    typedef T value_type;
};

上述还有一个问题,如果是指向常数对象的指针(pointer-to-const)

iterator_traits<const int*>::value_type

那萃取出来的,就是一个pointer-to-const的迭代器,无法赋值的临时变量不是我们的预期,需要另外设计一个版本

template <class T>
struct iterator_traits<const T*>{
    typedef T value_type;
};

通过上述方法萃取出来的value_type就是一个non-const类型。

 

这篇关于笔记:STL学习(二)-- 迭代器和traits的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!