一、traits简介
traits 是一种技法,简单说就是提取传入对象的对应返回类型。STL的算法和容器是分离的,两者通过迭代器链接。所以算法的实现并不会知道被传进来什么。traits相当于在接口和实现之间加一层封装,来隐藏一些细节并协助调用合适的方法,并附带上一些技巧(偏特化等)。
若使用迭代器时,需要使用其所指之物的型别,即算法中需要声明一个迭代器所指之型别的对象时,该怎么办呢?
1,使用 function template 的参数推导机制。
加一层封装之后,只需传入对象的引用即可,无需每一次都显式的指出迭代器指向对象的型别。但是,function template只能推导参数,无法推导函数的返回值类型。
2,为 class type 声明内嵌型别
通过声明内嵌型别,函数 function template就可以根据该型别返回正确型别的返回值。但是,不是所有的迭代器都是 class type的,原生指针就不行!怎么办呢?
3,偏特化 -- 在特化的基础上加一些限制
func在调用 I 的时候,首先把 I 传到traits中,然后 traits 匹配到最合适的 value_type(traits会优先匹配最特别的版本)。这样当传入一个原生指针的时候,首先匹配的是带有<T*>的偏特化版本,这样 value_type就是T,而不是没有事先声明的I::value_type。这样函数就可以使用 typename iterator_traits<I>::value_type来知道返回类型。
二、 traits的简单使用
1,使用traits在编译期就完成程序的分流,提高程序执行效率。
假设我们针对不同的迭代器类型编写了不同的处理函数,并对外暴露了一个公共接口。在该接口接收到参数时,它需要:
- 判断参数属于哪一类迭代器
- 根据迭代器类别调用相应的函数
但是,上述判断迭代器的操作发生在执行期,若我们能够在编译期就选择好正确的版本,就可以提高程序效率。通过重载函数,将迭代器类型传入,并对外暴露唯一的接口。
traits 一方面在面对不同的输入类时,能够找到合适的返回型别;另一方面,当型别对应有不同的实现函数时,能起到一个提取型别然后分流的作用。
2,代码示例
#include <iostream>
using namespace std;
/*先定义一些tag*/
struct A {};
struct B : A{};
/*假设有一个未知类*/
template <class AorB>
struct unknown_class {
typedef AorB return_type;
};
/*特性萃取器*/
template <class unknown_class>
struct unknown_class_traits {
typedef typename unknown_class::return_type return_type;
};
/*特性萃取器 —— 针对原生指针*/
template <class T>
struct unknown_class_traits<T*> {
typedef T return_type;
};
/*特性萃取其 —— 针对指向常数*/
template <class T>
struct unknown_class_traits<const T*> {
typedef const T return_type;
};
/*决定使用哪一个类型*/
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
return_type(unknown_class) {
typedef typename unknown_class_traits<unknown_class>::return_type RT;
return RT();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, A) {
cout << "use A flag" << endl;
return A();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, B) {
cout << "use B flag" << endl;
return B();
}
template <class unknown_class, class T>
T
__func(unknown_class, T) {
cout << "use origin ptr" << endl;
return T();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
func(unknown_class u) {
typedef typename unknown_class_traits<unknown_class>::return_type return_type;
return __func(u, return_type());
}
int main() {
unknown_class<B> b;
unknown_class<A> a;
//unknown_class<int> i;
int value = 1;
int *p = &value;
A v1 = func(a);
B v2 = func(b);
int v3 = func(p);
}