要想深入的理解STL的迭代器、分配器等,就必须了解C++模板编程中的一个技巧——Traits。

1、问题的提出

C++的模板特性为泛型编程提供了支持。这样我们就可以编写更加通用的代码,而不必过分去关心参数的类型。然而事实却是,类型的不同,很多时候却影响到了算法中的某个小小的实现。举个标准库里的类string,wstring。

其实它们对应的是两个模板,前者单字符,后者宽字符。

typedef basic_string<char, char_traits<char>, allocator<char> > string;typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring;

模板basic_string需要有一个得出字符串长度的函数length,那么问题就来了。因为char和wchar_t所对应的求长度API并不一样。前者是strlen,后者是wcslen。

正是为了解决这样类似的问题,C++中的traits技巧被提炼出来了。

2、解决方法

因为模板参数的类型不同,可能会影响到模板中具体的算法,那么我们就需要把这些与模板参数相差的方法从模板basic_string中提取出来,而保证basic_string算法的一致不受参数类型不同的影响。而上面的char_traits模板即是把与模板参数相差的方法都封装起来了。如果定义这样一个模板.

template<class _Elem>
struct char_traits
{
static void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right){        // assign an element
_Left = _Right;
}
static bool __CLRCALL_OR_CDECL eq(const _Elem& _Left, const _Elem& _Right)
{        // test for element equality
return (_Left == _Right);
}
//……
//……
//…..
static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
{        // find length of null-terminated sequence
//                _DEBUG_POINTER(_First);
size_t _Count;
for (_Count = 0; !eq(*_First, _Elem()); ++_First)
++_Count;
return (_Count);
}
};

这里的legnth实现是一个通用算法循环遍历,并没有使用系统的strlen,wcslen,效率相对低一些。那么如果我一定要使用strlen,wcslen呢?

这里就需要用到模板的特化,也即指定模板的参数类型。

        // STRUCT char_traits<wchar_t>template<> struct  char_traits<wchar_t>{    // properties of a string or stream wchar_t elementstatic void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right){    // assign an element_Left = _Right;}static bool __CLRCALL_OR_CDECL eq(const _Elem& _Left, const _Elem& _Right){    // test for element equalityreturn (_Left == _Right);}……………..static size_t __CLRCALL_OR_CDECL length(const _Elem *_First){    // find length of null-terminated sequence//        _DEBUG_POINTER(_First);return (::wcslen(_First));}};// STRUCT char_traits<char>template<> struct  char_traits<char>{    // properties of a string or stream wchar_t elementstatic void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right){    // assign an element_Left = _Right;}static bool __CLRCALL_OR_CDECL eq(const _Elem& _Left, const _Elem& _Right){    // test for element equalityreturn (_Left == _Right);}……………..static size_t __CLRCALL_OR_CDECL length(const _Elem *_First){    // find length of null-terminated sequence//        _DEBUG_POINTER(_First);return (::strlen(_First));}};

当实现了上面两个特化的模板之后,在模板basic_string中,我们如果需要知道当前模板参数类型的字符串长度时,只需要调用char_traits::length()就可以调用到正确的函数了。

3、总结

通过以上的事例,我们可以看出,具体的traits技巧非常简单。也就是将因为模板形参(包括类型形参、非类型形参)不同而导致的不同,抽取到新的模板中去,然后通过模板的特化(全特化、偏特化均可,至少有一个模板形参不同即可)来分别实现其不同。 这一类的模板,都会在命名中加上traits以示区别,所以也会把运用这一类方法称为C++的traits技术。traits技术更展现出了一种编程的思想,也即将相同的提出复用,将不同的部分通过接口来实现。将模板形参与基不同的实现绑定在一起,其实与设计模式中的状态模式很相似,都体现出了相同的编程思想。只不过前者是编译时确定的,后者则是运行时确定的。

4、注意

  1. Boost中有这样一个例子。

    template< typename T >
    struct is_pointer{
    static const bool value = false;
    };
    template< typename T >
    struct is_pointer< T* >{
    static const bool value = true;
    };

    这样我就可以通过is_pointer<T>::value来判断当前类型是否为指针类型。

  2. 非类型模板形参

    Template<bool b>
    Struct algo_sort
    {Template<typename T>Static void sort(T& obj){Quick_sort(obj);}
    }Template<>
    Struct algo_sort<true>
    {Template<typename T>Static void sort(T& obj){Select_sort(obj);}
    }

    这样就能够模板形参调用不同的排序方法了.

  3. 模板形参不仅仅与变量方法有关,还可能与类型有类.

    template< typename T >
    struct STRUCT_TYPE
    {typedef int MY_TYPE;typedef LONGLONG POWER_TYPE;
    };
    template<>
    struct STRUCT_TYPE<double>
    {typedef float MY_TYPE;typedef double POW_TYPE;
    };
    template< typename T >
    struct STRUCT_ALGO
    {// 下面的Typename是指示T::MY_TYPE是一个类型而不是成员变量// 在VS2005中加与不加均可
       typedef typename T::MY_TYPE myType;typedef T::POWER_TYPE powType;powType GetPow(const myType& value){return value*value;}
    };

    这样我们甚至可以将模板形参关联的变量类型也可以抽离出来,以提高模板的通用性.

转载于:https://www.cnblogs.com/feihe0755/p/4491769.html

C++ Traits技术相关推荐

  1. 【转】C++ traits技术

    [转]C++ traits技术 https://www.cnblogs.com/mangoyuan/p/6446046.html posted on 2018-08-06 19:31 时空观察者9号 ...

  2. 使用traits技术表现迭代器类型 iterator_category

    1.STL的迭代器类型标识,和容器中的迭代器类型. 2.使用trait技术实现stl的advance功能. 3.迭代器trait中的其他类型定义. 1.STL的迭代器类型标识,和容器中的迭代器类型. ...

  3. 萃取(traits)技术概念、范例等

    一.类型萃取范例 1.通过萃取接口中的 value 值为true,false 我们就可以萃取出很多有用的信息. #include <iostream> #include <futur ...

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

    当函数,类或者一些封装的通用算法中的某些部分会因为数据类型不同而导致处理或逻辑不同(而我们又不希望因为数据类型的差异而修改算法本身的封装时),traits会是一种很好的解决方案.(类型测试发生在编译期 ...

  5. 《STL源码剖析》学习--traits

    在本书迭代器一节提到了Traits编程技法,将其誉为stl源码门匙,在<C++编程思想>一书中,将其列为模板编程中的习语"特征",这里进行总结. traits技术 也往 ...

  6. 读书笔记 effective c++ Item 47 使用traits class表示类型信息

    STL主要由为容器,迭代器和算法创建的模板组成,但是也有一些功能模板.其中之一叫做advance.Advance将一个指定的迭代器移动指定的距离: 1 template<typename Ite ...

  7. [技术] OIer的C++标准库 : STL入门

    注: 本文主要摘取STL在OI中的常用技巧应用, 所以可能会重点说明容器部分和算法部分, 且不会讨论所有支持的函数/操作并主要讨论 C++11 前支持的特性. 如果需要详细完整的介绍请自行查阅标准文档 ...

  8. java traits_Traits技术初探

    概述:traits是一种特性萃取技术,它在Generic Programming中被广泛运用,常常被用于使不同的类型可以用于相同的操作,或者针对不同类型提供不同的实现.traits在实现过程中往往需要 ...

  9. C++11 类型支持之type traits

    文章目录 一.type_traits是什么 二.type_traits通常用来做什么 三.辅助基类 四.类型相关判断信息获取 4.1 判断基础类型类别 4.1 判断组合类型类别 4.3 判断类型的属性 ...

最新文章

  1. python编译环境搭建_python开发环境搭建
  2. 知道邻边和斜边求角度_从数学史角度看数系发展
  3. 谈谈UIView的几个layout方法-layoutSubviews、layoutIfNeeded、
  4. 数据包发包工具bittwist
  5. 数据库不推荐使用外键的9个理由!
  6. 同步 GIT@OSC 实现MARKDOWN文件发布或更新到CSDN博客中
  7. 玻璃体混浊不要转眼球
  8. python选择语句_3.1Python的判断选择语句
  9. Windows 10如何连接和使用局域网内的打印机(非网络打印机)亲测有效、绝对管用,不定时更新!!!(更新日期2021.09.14,如有不会的可以直接私我)
  10. 小米2S ROM重分区
  11. 全国一级计算机基础及ps题目,一级计算机基础及Photoshop应用模拟试题(14)
  12. 安卓苹果均兼容的移动版CAD看图软件——迅捷CAD看图
  13. 读书笔记—《雷达信号处理基础》第一章 雷达系统与信号处理概述
  14. 球面坐标系转换为笛卡尔坐标系
  15. canva怎么拼接图片_canvas图片拼接(横向)
  16. 虚拟地址如何访问到物理地址
  17. 浏览器打开时总是hao123.com的网站解决办法
  18. SWUST#954: 单链表的链接
  19. MySQL 8.0初体验
  20. 交通元宇宙的技术与应用(附下载)

热门文章

  1. php windowcrlf和unix,文件格式unix与dos转换,CRLF与LF的区别查看
  2. python zope 工作流_使用C语言来扩展Python程序和Zope服务器的教程
  3. anchor锚点 antvue_浅谈vue 锚点指令v-anchor的使用
  4. STM8 ADC转换模式-------单次扫描模式
  5. STM8 ADC转换模式-------单次模式
  6. 超实用的浏览器插件:CSDN 一键搜索、自定义工具、全站去广告、一键美化等
  7. FPGA学习笔记---用Quartus II生成输入输出框图
  8. Linux中安装开源JDK(windows的JDK只能安装半开源)
  9. NYOJ-疯牛(贪心)
  10. 发哥推荐的linux网站,记录一下