博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ Traits技术
阅读量:5159 次
发布时间:2019-06-13

本文共 4245 字,大约阅读时间需要 14 分钟。

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

1、问题的提出

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

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

typedef basic_string
, allocator
> string;typedef basic_string
, allocator
> wstring;

 

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

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

2、解决方法

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

template
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 equalityreturn (_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
template<> struct char_traits
{ // properties of a string or stream wchar_t element 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); return (::wcslen(_First)); } }; // STRUCT char_traits
template<> struct char_traits
{ // properties of a string or stream wchar_t element 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); 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
    Struct algo_sort{ Template
    Static void sort(T& obj) { Quick_sort(obj); }}Template<>Struct algo_sort
    { Template
    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
    { 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

你可能感兴趣的文章
PHPSTORM/IntelliJ IDEA 常用 设置配置优化
查看>>
python爬虫入门10.16
查看>>
MVC,MVP 和 MVVM 的图示
查看>>
Sql Server 的DataReader 与 DataSet
查看>>
关于NSA的EternalBlue(永恒之蓝) ms17-010漏洞利用
查看>>
数据结构之B进制(确定进制)
查看>>
python小白-day9 数据库操作与Paramiko模块
查看>>
git push 冲突
查看>>
自然连接(natural join)
查看>>
Python pyspider HTTP 599 错误
查看>>
Data visualization 课程 笔记3
查看>>
Lucene的搭建(3)
查看>>
jsp---tomcat===》》内置对象
查看>>
Linux的文件与目录管理 - 鸟哥Linux私房菜第七章 - 思维导图
查看>>
求数组中最长递增子序列
查看>>
java总结第二次(剩余内容)//类和对象1
查看>>
c++语言中的遍历
查看>>
layui table 行按钮事件,启用禁用切换
查看>>
带参数的文件上传方法&后台接收
查看>>
私有作用域&闭包机制
查看>>