STL经常需要获取迭代器型别来进行一系列算法设计,简单总结一下书所对于型别推导提到的思想
迭代器获取其所指元素的型别
- 1.
一 利用 function template 的自变量推导( argument deducation)机制。
template <class I, class T>
void func_impl(I iter, T t)
{
T tmp; // 这里解决了问题。 T就是迭代器所指之物的型别,ᴀ例为 int
// ... 这里做原ᴀ func() 应该做的全部工作
};
template <class I>
inline void func(I iter)
{
func_impl(iter, *iter); // func 的工作全部移往 func_impl
}
int main()
{
int i;
func(&i);
}
使用func()来包装func_impl(),func函数对外。只要调用func()便可以通过func_impl推导出型别T。但是这中方法并不健全,当func的参数为函数返回值就行不通了。
-
2.
声明内嵌型别
template <class T>
struct MyIter
typedef T value_type;
T* ptr;
MyIter(T* p=0) : ptr(p) { }
T& operator*() const { return *ptr; }
// ...
};
template <class I>
typename I::value_type func(I ite)
{ return *ite; }
// ...
MyIter<int> ite(new int(8));
cout << func(ite); //输出: 8
但是 实际上 要使迭代器有内嵌型别,迭代器本身就必须是一个struct或者class,但是像原生指针并不是class这种类型就无法定义内嵌型别,因此通过3
3.
偏特化
template<typename T> //1
class C { ... };
template<typename T> //2
class C<T*> { ... };
如上,2为1偏特化,可以通过2设计T指针的偏特化迭代器。解决了指针无法定义内嵌型别的问题。
关于traits ,这个地方比上面难理解一些 多写一点
首先需要明白traits 解决的问题,对于T
举个例子 如果我要实现一个模板类,在这个模板类实现一个函数sum()来计算两个成员变量的和,其中两个成员变量均为T类型。sum要求如下
1当T为float类型时候,要求sum()返回类型为int
2当T为其他类型的时候,要求sum( )返回类型为T
如果只是单纯实现2的话,很容易做到,但是1的话不属于2范围,这时候就需要用到偏特化。
实现如下
#include<iostream>
template <typename T>
struct Traits{
typedef T _type;
};
template<>
struct Traits<float>{
typedef int _type;
};
template <typename T>
class A
{
public:
A(T a,T b):data_a(a),data_b(b){};
typename Traits<T>::_type sum(){return data_a+data_b;}
private:
T data_a,data_b;
};
int main()
{
A<double>Obj_d(1.3,1.5);
A<float>Obj_f(1.3,1.5);
std::cout<<Obj_d.sum()<<" "<<Obj_f.sum(); //输出为2.8 2
return 0;
}
理解了traits的本意,那么我们可以对T* 进行偏特化,并通过trait取出value(T)类型来定义func2,同样也适用于const T*
#include<iostream>
using namespace std;
template <class T>
struct MyIter{
typedef T Iter_type;
T* ptr;
MyIter(T* p=0):ptr(p){}
T& operator*() const{
return *ptr;
}
};
template <class T>
struct MyIter<T*>{
typedef T Iter_type;
T* ptr;
MyIter(T* p=0):ptr(p){}
T& operator*() const{
return *ptr;
}
};
template<class T>
struct traits{
typedef typename T::Iter_type traits_type;
};
template<class T>
struct traits<T*>{
typedef T traits_type;
};
//template<class T>
//struct traits<const T*>{
// typedef T traits_type;
//};
template <class I>
typename traits<I>::traits_type func(I iter){
return *iter;
}
int main(){
MyIter<int>iter1(new int(8));
MyIter<int*>iter2(new int(8));
cout<<func(iter1)<<endl<<func(iter2);
}
迭代器
5个内嵌类型
- value type 用来表示迭代器所指对象的型别;
- difference type 用来表示两个迭代器之间的距离;
- reference 为引用类型;
- pointer 为指针类型;
- iterator_category 表明迭代器的类型
迭代器的五种类型
1. Input Iterator:这种迭代器所指对象,不允许外界改变,只读(read only);
2. Output Iterator:唯写(write only);
3. Forward Iterator:允许「写入型」算法(例如 replace())在此种迭代器所形成的区间上做读写动作;
4. Bidirectional Iterator:可双向移动。某些算法需要逆向走访某个迭代器区间(例如逆向拷贝某范围内的元素),就可以使用 Bidirectional Iterators;
5. Random Access Iterator:前四种迭代器都只供应一部份指标算术能力(前3
种支持 operator++ ,第4种再加上 operator–),第5种则涵盖所有指标算术能力,包括 p+n, p-n, p[n], p1-p2, p1
通过继承机制,
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag { };
struct random_access_iterator_tag : public bidirectional_iterator_tag { };
以上结构体仅作为标记存在,通过一个作为标记参数来重载函数
对外接口使用traits机制,在编译期确定调用的重载函数。
__type_traits
traits的其他用途,用于获取是否有如下内容,提高在程序运行期的效率。
has_trivial_default_constructor;
has_trivial_copy_constructor;
has_trivial_assignment_operator;
has_trivial_destructor;
is_POD_type;