Traits技术在标准库Iterator中引入过程以及使用
一、Traits技术
简单的说,traits是一种萃取类特性的技术,它通过模版、typedef以及模版专门化等技术完成特性萃取,如何实现以及如何运用?
二、标准库Iterator引入traits过程
标准库中迭代器Iterator发挥了巨大作用,他将容器和算法进行解耦合,在他们之间起到纽带的作用,在软件设计中非常值得学习。那么迭代器如何获取自己所指向的类型呢?
这里主要运用了模版的类型推到作用,对于一个函数模版来说:
template<class T>
void Fun(const T&) {
T tmp;
...
}
通过模版的方法可以声明某类型的变量,因此产生了如下想法
template<class Iter, class T>
void Fun_real(Iter iter, T) {
T tmp;
...
}
template<class Iter>
void Fun(Iter iter) {
return Fun_real(iter, *iter);
}
通过模版的方法可以顺利推到出类型T,这样就解决了在只知道迭代器的情况下如何获取迭代器所指向的类型。此时问题又出现了,如何推导出函数的返回值呢?
通过申请内嵌类型貌似可以解决这个问题,例如:
template<class T>
class {
typedef T value_type;
...
}
template<class Iter>
typename Iter::value_type Fun(Iter iter) {
return *iter;
}
需要注意的是fun返回值类型必须加上typename,否则编译器在具体化类型T之前对Iter不知道。貌似是一个非常好的解决方案,但是问题又出现了,并发所有的类型都为class类型,原生指针类型就不是(对于指针类型比较特殊T*的指针,其指向的类型为T)
此时强大的Traits出现了,且看如何解决原生指针问题的。
template <class T>
struct iterator_traits {
typedef typename T::value_type value_type
}
template<>struct iterator_traits<T*> {
typedef T value_type;
}
template<class T>
class Iter{
typedef T value_type;
}
template<class Iter>
type_name iterator_traits<Iter>::value_type(Iter iter) {
return *iter
}
通过iteratro_traits包装了一层,然后通过模版的专门化技术解决了该问题,具体分析一下当Iter的模版参数为T*时,iterator_traits<T*>就会被调用,这样T就为value_type。通过这样间接的起到了指针指向的类型。
可见Traits可以萃取到迭代器的特性,这里指的是迭代器的指向的类型。当然迭代器内定义了很多特性,例如:value_type\difference_type\pointer\reference\iterator_category等。
三、Traits使用
上面介绍了在标准库迭代器是如何引入traits的,在实际应用中,如果有类似需要萃取类的某种特性的需求,均可以采用traits技术。例如我们要萃取类是否有加N(N为一个int变量)的功能。
#include <iostream>
using namespace std;
struct yes_type {};
struct no_type {};
// 默认情况下,均没有改功能
template <class T>
struct add_n_traits {
typedef no_type has_add_n;
};
// 通过专门化,认为int有该功能
template<>
struct add_n_traits<int> {
typedef yes_type has_add_n;
};
template<class T>
class MyAdd {
public:
// 这里通过traits萃取到不同类型是否有加n这个功能
void Add(int n) {
AddImpl(n, typename add_n_traits<T>::has_add_n());
}
private:
// 这里要分别进行处理
void AddImpl(int n,yes_type) {
std::cout << "yes_type:add n" << std::endl;
}
void AddImpl(int n,no_type) {
std::cout << "no_type:add n" << std::endl;
}
};
class ForTest {
};
int main() {
MyAdd<int> int_add;
int_add.Add(1);
MyAdd<ForTest> test_add;
test_add.Add(1);
return 0;
}
输出结果为:
yes_type:add n
no_type:add n
四、总结
看到这里你是否认为traits也不过如此,确实仅此而已。但是如何将该技术运用到实际是一个很大的挑战。