目录
第三章
3.4 traits
iterator_traits<T>
为了获取iterator所指内容的型别,有了iterator_traits
my_define.h
#ifndef CH1_MY_DEFINE_H
#define CH1_MY_DEFINE_H
template<class T>
struct my_iterator_traits{
typedef typename T::value_type value_type;
};
template<class T>
struct my_iterator_traits<T*>{
typedef T value_type;
};
#endif //CH1_MY_DEFINE_H
这里使用了偏特化。限定了T必须为指针类型。
template<class T>
struct my_iterator_traits<T*>{
typedef T value_type;
};
基于此,可以对指向const T
的指针(pointer to const)也加以偏特化。(因为希望萃取出来的value_type
是T
而不是const T
)
template<class T>
struct my_iterator_traits<const T*>{
typedef T value_type;
};
main.cpp
#include <iostream>
#include <vector>
#include "my_define.h"
using namespace std;
template<class I>
typename my_iterator_traits<I>::value_type
function(I a) {
return *a;
}
int main() {
int *aa = new int;
*aa = 1;
cout<< function(aa)<<endl;
int a = 1;
vector<int> arr(1,0);
auto iter=arr.begin();
cout<< function(iter)<<endl;
return 0;
}
iterator_category
因为有不同的数据结构,那么对使用迭代器遍历时会有不同的效率。正如书中所说,若能萃取出迭代器类型,就能执行与它最匹配的迭代器移动方法。
最基础的想法是,用一个函数专门完成转发。
template<class InputIterator,class Distance >
void advance(InputIterator& i,Distance n) {
if(is_random_access_iterator(i)) {
//balabala...
} else if(is_bidirectional_iterator(i)) {
//balabala...
} else {
// ...
};
};
但是在执行时期才决定使用哪一个版本,拉跨效率。
于是要是能把迭代器类型作为参数传入就好了。
于是使用了class来代表五种迭代器类型
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 {};
那么advance()函数写成如下
template<class InputIterator,class Distance >
void advance(InputIterator& i,Distance n) {
__advance(i,n,
iterator_traits<InputIterator>::iterator_category(i));
};
iterator_category()
并有如下获取迭代器类型的函数
template<class T>
inline typename iterator_traits<T>::iterator_category
iterator_category(const I&) {
typedef typename iterator_traits<T>::iterator_category category;
return category();//返回一个category临时对象。但由于是空struct,应该是无负担的
}
value_type()
template<class Iterator>
inline typename iterator_traits<Iterator>::value_type*
value_type(const Iterator&) {
return static_cast<typename
iterator_traits<Iterator>::value_type*>(0);
}
__type_traits<T>
__type_traits<T>
用于提取迭代器型别的特性。据书所述,主要是区分是不是POD(Plain Old Data)型别。
POD型别
struct __true_type {};
struct __false_type {};
那么之后这样定义就可以了。
template<class type>
struct __type_traits {
typedef __true_type this_dummy_member_must_be_first;
/*没看懂书中注释说的啥...*/
//全部定义为false,保守起见。
typedef __false_type has_trivial_default_constructor;//默认构造
typedef __false_type has_trivial_copy_constructor;//拷贝构造
typedef __false_type has_trivial_assignment_operator;//赋值
typedef __false_type has_trivial_destructor;//析构
typedef __false_type is_POD_type;
很tricky,之后对基本scalar类型再定义一份特化版本就好了。比如
template<>
struct __type_traits<char> {
typedef __true_type has_trivial_default_constructor;//默认构造
typedef __true_type has_trivial_copy_constructor;//拷贝构造
typedef __true_type has_trivial_assignment_operator;//赋值
typedef __true_type has_trivial_destructor;//析构
typedef __true_type is_POD_type;
省略一万个类型…
总结
总的来说,使用一个class来作为tag标记,有点出乎意料(是我太菜了。。)开启了新世界的大门…