C++ Traits技术

转载 2015年07月06日 19:49:13

Traits技术

Traits技术 - woaidongmao - C++博客
http://www.cppblog.com/woaidongmao/archive/2008/11/08/66367.html

.概念

Trait的中文意思就是特性,Traits就像特性萃取机,榨取不同类的特性,以便能统一处理。Traits依靠显式模板特殊化(explicit template specialization)来把代码中因类型不同而发生变化的片断拖出来,用统一的接口来包装。这个接口可以包含一个C++类所能包含的任何东西:内嵌类型,成员函数,成员变量,作为客户的模板代码可以通过traits模板类所公开的接口来间接访问之。花了点时间,憋了一个示例程序,虽然没什么实际意义,但对于理解traits来说,可能会有帮助。

#include <iostream>

class CM {};

class CA {};

class CIM {};

template< typename T >

class Traits

{

public:

    typedef unsigned int ValueType;

    Traits() : m_rate( 2 ) {}

    ValueType ComputeValue( ValueType value ) { return value * m_rate; }

private:

    ValueType m_rate;

};

template<>

class Traits< CM >

{

public:

    typedef double ValueType;

    Traits() : m_rate( 1.2 ) {}

    ValueType ComputeValue( ValueType value ) { return value * m_rate; }

private:

    ValueType m_rate;

};

template<>

class Traits< CA >

{

public:

    typedef int ValueType;

    Traits() : m_rate( -1 ) {}

    ValueType ComputeValue( ValueType value ) { return value * m_rate; }

private:

    ValueType m_rate;

};

template< typename T >

struct ValueCount

{

    void result()

    {

        Traits< T > traits;

        Traits< T >::ValueType value = static_cast< Traits< T >::ValueType >( 2 );

        std::cout << traits.ComputeValue( value ) << std::endl;

    }

};

int main()

{

    ValueCount< CIM > cim;

    cim.result();

    ValueCount< CM > cm;

    cm.result();

    ValueCount< CA > ca;

    ca.result();

    return 0;

}

代码中的Tratis类对于CA和CM有显式的特化实现,其中ValueType类型和rate与默认的实现不同,在类ValueCount中,利用Tratis对不同类型用一个统一的接口符号处理。程序的运行结果是4,2.4,-2。(这是我的第一个模版程序J)

2.SGI STL中的__type_traits

在SGI实现版的STL中,为了获取高效率,提供了__type_traits,用来提取类的信息,比如类是否拥有trival的构造、析构、拷贝、赋值操作,然后跟据具体的信息,就可提供最有效率的操作。以下摘录cygwin的gcc3.3源码,有改动,在<type_traits.h>中。

struct __true_type {};

struct __false_type {};

template <class _Tp>

struct __type_traits {

    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;

};

对于普通类来讲,为了安全起见,都认为它们拥有non-trival的构造、析构、拷贝、赋值函数,POD是指plain old data。接下来对C++的原生类型(bool,int, double之类)定义了显式的特化实现,以double为例:

template<> struct __type_traits<long double> {

    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;

};

还有,对所有的原生指针来讲,它们的构造、析构等操作也是trival的,因此有:

template <class _Tp>

struct __type_traits<_Tp*> {

    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_algobase.h>中copy的部分代码来说明对__type_traits的应用。

template<typename _Tp>

inline _Tp*

__copy_trivial(const _Tp* __first, const _Tp* __last, _Tp* __result)

{

    memmove(__result, __first, sizeof(_Tp) * (__last - __first));

    return __result + (__last - __first);

}

template<typename _Tp>

inline _Tp*

__copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __true_type)

{ return __copy_trivial(__first, __last, __result); }

template<typename _Tp>

inline _Tp*

__copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __false_type)

{ 另外处理; }

template<typename _InputIter, typename _OutputIter>

inline _OutputIter

copy (_InputIter __first, _InputIter __last, _OutputIter __result)

{

    typedef typename iterator_traits<_InputIter>::value_type _ValueType;

    typedef typename __type_traits<_ValueType>::has_trivial_assignment_operator _Trivial;

    return __copy_aux(__first, __last, __result, _Trivial());

}

Copy函数利用__type_traits判断当前的value_type是否有trival的赋值操作,如果是,则产生类__true_type的实例,编译时选择__copy_trivial函数进行memmove,效率最高。如果是non-trival的赋值操作,则另作处理,效率自然低些。__true_type和__false_type之所以是类,就因为C++的函数重载是根据类型信息来的,不能依据参数值来判别。使用SGI STL时,可以为自己的类定义__type_traits显式特化版本,以求达到高效率。

3. STL中的iterator_traits

iterator_traits提供5个特性的提取,至于为什么是5个以及iterator的分类,以后再议。代码包含在<stl_iterator_base_types.h>中。

template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,

typename _Pointer = _Tp*, typename _Reference = _Tp&>

struct iterator

{

    typedef _Category iterator_category;

    typedef _Tp value_type;

    typedef _Distance difference_type;

    typedef _Pointer pointer;

    typedef _Reference reference;

};

template<typename _Iterator>

struct iterator_traits {

    typedef typename _Iterator::iterator_category iterator_category;

    typedef typename _Iterator::value_type value_type;

    typedef typename _Iterator::difference_type difference_type;

    typedef typename _Iterator::pointer pointer;

    typedef typename _Iterator::reference reference;

};

原生指针(如int*,double*)也是iterator,但它不是类,无法提取出value_type,所以要对原生指针和const原生指针进行显式特化。

template<typename _Tp>

struct iterator_traits<_Tp*> {

    typedef random_access_iterator_tag iterator_category;

    typedef _Tp value_type;

    typedef ptrdiff_t difference_type;

    typedef _Tp* pointer;

    typedef _Tp& reference;

};

template<typename _Tp>

struct iterator_traits<const _Tp*> {

    typedef random_access_iterator_tag iterator_category;

    typedef _Tp value_type;

    typedef ptrdiff_t difference_type;

    typedef const _Tp* pointer;

    typedef const _Tp& reference;

};

现在,对于所有的iterator都可以正确的提取出以上5个特性。

下面解释iterator_category,iterator共分为5类,input_iterator,output_iterator,forward_iterator,bidirectional_iterator,random_access_iterator。其中forward_iterator是input_iterator和output_iterator的强化(refinement),bidirectional_iterator是forward_iterator的强化,random_access_iterator是bidirectional_iterator的强化。由于5种iterator的性质的同异,需要对它们的种类进行区分,制定特化的函数以达到最优的效率,就像上一节的type_traits一样。需要强调的是,强化不是继承,C++重载机制支持对继承类的正确选择。由于不同iterator有共同的操作,在iterator_category中建立继承关系可以简化大部分特化函数的实现。

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 {};

由iterator_category带来的效率优化,可由在<stl_iterator_base_funcs.h>内的两个函数看出,一个是用来计算两个iterator的距离__distance,一个是将iterator累进n次的__advance。列举__distance的代码如下,有改动。

template<typename _InputIterator>

inline typename iterator_traits<_InputIterator>::difference_type

__distance(_InputIterator __first, _InputIterator __last,

input_iterator_tag)

{

    typename iterator_traits<_InputIterator>::difference_type __n = 0;

    while (__first != __last) {

        ++__first; ++__n;

    }

    return __n;

}

template<typename _RandomAccessIterator>

inline typename iterator_traits<_RandomAccessIterator>::difference_type

__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,

random_access_iterator_tag)

{ return __last - __first; }

template<typename _Iter>

inline typename iterator_traits<_Iter>::iterator_category

__iterator_category(const _Iter&)

{ return typename iterator_traits<_Iter>::iterator_category(); }

template<typename _InputIterator>

inline typename iterator_traits<_InputIterator>::difference_type

distance(_InputIterator __first, _InputIterator __last)

{ return __distance(__first, __last, __iterator_category(__first)); }

4. traits技术还有很夸张的应用。《C++ 设计新思维:范型编程与设计模式之应用》中有体现,或者,泛型编程还得依赖traits技术,也许以后的C++会从语言特性上支持traits。

《STL源码剖析》学习之traits编程

在设计模式中有一种模式叫迭代器模式,简单来说就是提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素,这种设计思维在STL中得到了广泛的应用,是STL的关键所在,通...
  • shudou
  • shudou
  • 2013年09月15日 20:04
  • 8274

Traits技术:类型的if-else-then(STL核心技术之一)

Traits: 类型的else-if-then机制Andrei AlexandrescuAndrei Alexandrescu在位于华盛顿州西雅图市的RealNetworks公司中任开发经理。什么是t...
  • myan
  • myan
  • 2001年03月15日 10:57
  • 6300

我对C++ Traits编程技法的一点点理解

第一次听说traits是在一次电话面试中,当时还没有听说过这个词。之后查过资料,但也不是十分明白,直到今天重新看了一下《STL源码剖析》,稍微有一些想法。 1. traits是模板编程里面的一个编程...
  • erorr
  • erorr
  • 2014年04月13日 01:37
  • 1458

C++ 模板类型萃取技术 traits

自从C++中引入了template后,以泛型技术为中心的设计得到了长足的进步。STL就是这个阶段杰出的产物。STL的目标就是要把数据和算法分开,分别对其进行设计,之后通过一种名为iterator的东西...
  • net_assassin
  • net_assassin
  • 2013年08月09日 16:20
  • 2331

C++ 中Traits技术 (2) —— 与迭代器

接着了解C++中的Traits技术。 Traits技术可以获取一个类型的相关信息。 比如针对一个泛型迭代器,类型参数T表示迭代器所指向的类型。 template class CMyIterat...
  • u013575812
  • u013575812
  • 2016年04月13日 23:57
  • 282

C++ 中Traits技术 (5) —— 关于STL中对迭代器封装的类型介绍

上一篇讲到traits的类型萃取,可将迭代器相关的类型获取用于变量声明和函数返回等操作。对于原生指针和const指针可以采用偏特化技术进行处理。 在STL中,对迭代器除了封装类型信息以外,还有一些...
  • u013575812
  • u013575812
  • 2016年04月19日 23:37
  • 483

C++ 中Traits技术 (3) —— 关于特化和偏特化

以下面这个例子为例进行说明: template class Test { public: static bool TestFun(const T& t); }; 特化,其实就是为模...
  • u013575812
  • u013575812
  • 2016年04月16日 20:27
  • 534

C++ Traits技术

原文地址:http://www.cppblog.com/woaidongmao/archive/2008/11/09/66387.html 概述: traits是一种特性萃取技术,它在Ge...
  • chaoojie
  • chaoojie
  • 2012年07月25日 10:52
  • 3920

c++ traits技术

Traits技术可以用来获得一个 类型 的相关信息的。 首先假如有以下一个泛型的迭代器类,其中类型参数 T 为迭代器所指向的类型: template typename T> class myI...
  • hy0736
  • hy0736
  • 2012年07月10日 12:03
  • 94

C++traits技术的理解

traits是c++中的自动类型推断,可以用来获得一个类型的相关信息。比如我们有一个泛型的迭代器类,其中T为所指向的类型。 template class myIterator { ... };当我...
  • qq100440110
  • qq100440110
  • 2016年07月07日 22:17
  • 729
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ Traits技术
举报原因:
原因补充:

(最多只允许输入30个字)