STL中的Traits编程技巧
2017-05-17 14:50
369 查看
《STL源码剖析》一书中提到Traits编程技法,它的作用是获取型别(associated type)的特性。这样讲比较抽象,到底什么是相应型别,或者到底什么时候需要用到Traits编程技法呢?先来看一个例子。
那么函数的返回类型的该怎么写呢?再往下看,如果这个Iterator由我们自己来实现(事实上stl的Iterator的实现和这个十分类似)
这里要注意一点,返回类型必须加上关键词
的用意在于告诉编译器这是一个型别,如此才能顺利通过。这样我们就可以通过func函数获取迭代器所指代的类型了。
但是这样还是有一个问题,并不是所有迭代器都是class type的。比如原生的指针就不是,这样就没有办法为它定义内嵌型别了。现在就轮到traits编程技法发挥作用的时候了:
现在我们可以利用模板的template partial specialization(偏特化)定义一个偏特化版的iterator_traits专门用于萃取原生指针的型别。
同理,对于指向常量的指针,我们也可以专门偏特化一个版本来萃取它的型别。
如果说iterator_traits负责萃取迭代器的特性,那么__type_traits则负责萃取型别的特性。这里所关注的型别特性有一下5个:
has_trivial_default_constructor
has_trivial_copy_constructor
has_trivial_assignment_operator
has_trivial_destructor
is_POD_type
有了这些型别特性,我们在对这个型别进行构造、析构、拷贝、赋值等操作时,就可宜采用最有效率的措施。比如对于has_trivial_copy_constructor,那么我只直接通过内存拷贝来实现对象拷贝以提高效率。
参照iterator_traits的经验,我们希望通过下面这样的方法来获取使用__type_traits
:
我们希望上式能够返回给我们一个对象的型别,而不是单纯的bool类型,这样编译器可以通过这个对象的型别来进行参数推导。为此,上述式子应该传回
这是两个空白classes,没有任何成员,我们知道编译器在进行参数推导的时候,并不会真的去生成一个对象,因此,这么做是不会带来额外负担的,却又能够标示真假。
下面就是SGI的
如果自己实现一个类,需要告诉STL这个类的特性,那么为这个类也特化一个模板就可以了。
iterator_traits
假设有这么一个函数,接受一个iterator,返回这个iterator所指代的类型,其实这个函数就是实现了typeof(),但是c++里面并没有typeof()操作符。vector<int> iv = {1, 2, 3, 4, 5}; vector<int>::Iterator it1 = iv.begin(), it2 = iv.end(); template<class iterator> // ret-type fun(iterator it) { // 函数体 }
那么函数的返回类型的该怎么写呢?再往下看,如果这个Iterator由我们自己来实现(事实上stl的Iterator的实现和这个十分类似)
template<class T> struct MyIter // 为了方便访问成员,用struct { typedef T value_type; // 内嵌声明(nested 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; }
这里要注意一点,返回类型必须加上关键词
typename,编译器并不知道
MyIter<I>::value_type代表的是一个型别或是一个
member function或是一个
data member。关键词
typename
的用意在于告诉编译器这是一个型别,如此才能顺利通过。这样我们就可以通过func函数获取迭代器所指代的类型了。
但是这样还是有一个问题,并不是所有迭代器都是class type的。比如原生的指针就不是,这样就没有办法为它定义内嵌型别了。现在就轮到traits编程技法发挥作用的时候了:
template <class I> struct iterator_traits { typedef typename I::value_type value_type; // 此处的typename和上文同理,不再赘述。 } // func可以这么写 template <class I> typename iterator_traits<I>::value_type func(I ite) { return *ite; }
现在我们可以利用模板的template partial specialization(偏特化)定义一个偏特化版的iterator_traits专门用于萃取原生指针的型别。
template <class T> struct iterator_traits<T*> { typedef T value_type; }
同理,对于指向常量的指针,我们也可以专门偏特化一个版本来萃取它的型别。
template <class T> struct iterator_traits<const T*> { typedef T value_type; }
__type_traits
这里再提一点题外话,《STL源码剖析》提到,stl只对迭代器加以规范,制定出iterator_traits这样的东西,SGI则把这种技法扩大到了迭代器以外,定义了__type_traits。双底线前缀值这是SGI STL内部特有的,不在STL的标准规划之中。如果说iterator_traits负责萃取迭代器的特性,那么__type_traits则负责萃取型别的特性。这里所关注的型别特性有一下5个:
has_trivial_default_constructor
has_trivial_copy_constructor
has_trivial_assignment_operator
has_trivial_destructor
is_POD_type
有了这些型别特性,我们在对这个型别进行构造、析构、拷贝、赋值等操作时,就可宜采用最有效率的措施。比如对于has_trivial_copy_constructor,那么我只直接通过内存拷贝来实现对象拷贝以提高效率。
参照iterator_traits的经验,我们希望通过下面这样的方法来获取使用__type_traits
:
__type_traits<T>::has_trivial_default_constructor __type_traits<T>::has_trivial_copy_constructor __type_traits<T>::has_trivial_assignment_operator __type_traits<T>::has_trivial_destructor __type_traits<T>::is_POD_type
我们希望上式能够返回给我们一个对象的型别,而不是单纯的bool类型,这样编译器可以通过这个对象的型别来进行参数推导。为此,上述式子应该传回
struct __true_type {}; struct __false_type {};
这是两个空白classes,没有任何成员,我们知道编译器在进行参数推导的时候,并不会真的去生成一个对象,因此,这么做是不会带来额外负担的,却又能够标示真假。
下面就是SGI的
__type_traits实现:
template <class type> struct __type_traits { typedef __true_type this_dummy_member_must_be_first; 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; } // 下面是<yupe_traits.h>对C++标量型定义的__type_traits的特化版的一个举例。 // __STL_TEMPLATE_NULL 定义为 template<> __STL_TEMPLATE_NULL 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; }
如果自己实现一个类,需要告诉STL这个类的特性,那么为这个类也特化一个模板就可以了。
相关文章推荐
- STL源码解析——traits(特性)编程技巧
- STl-traits编程技巧
- STL中迭代器与traits编程的技巧
- STL学习笔记:Iterator和Traits编程技巧
- STL中的traits编程技巧
- STL——迭代器与traits编程技法
- iterator与traits编程技巧
- 【深度探索STL】详解 traits 编程技法
- STL笔记:traits编程
- C++STL 编程技巧1 STL中各种排序算法的实现
- STL源码-iterator traits编程技法
- STL源码-iterator traits编程技法(续)
- 2013-04-21 STL之模板编程技巧
- STL三:Traits编程技法一
- STL-traits编程技法
- STL iterator和traits编程技法
- Traits 编程技法+模板偏特化+template参数推导+内嵌型别编程技巧
- STL源码分析--萃取编程(traits)技术的实现
- traits 编程技巧详解
- STL中迭代器概念与traits编程技法