C++ Traits技术
要想深入的理解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 = ; !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 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<char>
template<> struct char_traits<char>
{ // 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、注意
- 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来判断当前类型是否为指针类型。
非类型模板形参
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);
}
}这样就能够模板形参调用不同的排序方法了.
模板形参不仅仅与变量方法有关,还可能与类型有类.
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;
}
};这样我们甚至可以将模板形参关联的变量类型也可以抽离出来,以提高模板的通用性.
C++ Traits技术的更多相关文章
- STL源码分析《4》----Traits技术
在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...
- C++ traits技术浅谈
前言 traits,又被叫做特性萃取技术,说得简单点就是提取"被传进的对象"对应的返回类型,让同一个接口实现对应的功能.因为STL的算法和容器是分离的,两者通过迭代器链接.算法的实 ...
- 【转】traits技术及模板偏特化
#include <iostream> using namespace std; struct __xtrue_type { }; // define two mark-type stru ...
- C++ Traits 技术
Tarits.特性的复数. c++萃取技术就是指它. 实现方式是模板特化. STL中涉及到iterator的地方常常能用到它. gcc的STL与VS的STL略有区别. vs中下列代码,把鼠标放在ite ...
- [转]Traits 编程技法+模板偏特化+template参数推导+内嵌型别编程技巧
STL中,traits编程技法得到了很大的应用,了解这个,才能一窥STL奥妙所在. 先将自己所理解的记录如下: Traits技术可以用来获得一个 类型 的相关信息的. 首先假如有以下一个泛型的迭代器类 ...
- 读书笔记 effective c++ Item 47 使用traits class表示类型信息
STL主要由为容器,迭代器和算法创建的模板组成,但是也有一些功能模板.其中之一叫做advance.Advance将一个指定的迭代器移动指定的距离: template<typename IterT ...
- [技术] OIer的STL入门教程
注: 本文主要摘取STL在OI中的常用技巧应用, 所以可能会重点说明容器部分和算法部分, 且不会讨论所有支持的函数/操作并主要讨论 C++11 前支持的特性. 如果需要详细完整的介绍请自行查阅标准文档 ...
- c/c++ 模板与STL小例子系列<三> traits
c/c++ 模板与STL小例子系列 traits 对这个概念,还是处于懵逼的状态,初步体会就是,为了解决类型之间的转换问题. 从一个类型为A的指针,转化到类型为B的指针,中间需要用void*来作为中介 ...
- 《STL源码剖析》学习之traits编程
侯捷老师在<STL源码剖析>中说到:了解traits编程技术,就像获得“芝麻开门”的口诀一样,从此得以一窥STL源码的奥秘.如此一说,其重要性就不言而喻了. 之前已经介绍过迭代器 ...
随机推荐
- css3 钟表
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- redhat 挂载 iso文件 提示 mount :not a directory
- HTML5每日一练之figure新标签的应用
igure元素是一种元素的组合,可带有标题(可选).figure标签用来表示网页上一块独立的内容,将其从网页上移除后不会对网页上的其他内容产生影响.figure所表示的内容可以是图片.统计图或代码示例 ...
- 什么是ADB
ADB, Android Debug Bridge, 是一个client-server程序,可以用来和安卓设备交流 Client: 用来发送命令的,client运行在开发机器上(电脑cmd, adb ...
- POJ 2398 Toy Storage(计算几何,叉积判断点和线段的关系)
Toy Storage Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3146 Accepted: 1798 Descr ...
- FZU 2129 子序列个数 (递推dp)
题目链接:http://acm.fzu.edu.cn/problem.php?pid=2129 dp[i]表示前i个数的子序列个数 当a[i]在i以前出现过,dp[i] = dp[i - 1]*2 - ...
- How Tomcat Works(七)
本文接下来介绍并分析servlet容器,servlet容器是用来处理请求servlet资源,并为web客户端填充response对象的模块. servlet容器是org.apache.catalina ...
- 解决sencha touch显示.JSON包含中文数据时显示乱码问题
按照ST官方示例navigationview做的一个示例.数据源是一个.json文件.但是显示的时候如果.json文件里有中文则乱码.我知道是编码问题,但是不知道怎么改,如何改. 问了N个人最后解决方 ...
- 前端MVC学习总结(三)——AngularJS服务、路由、内置API、jQueryLite
一.服务 AngularJS功能最基本的组件之一是服务(Service).服务为你的应用提供基于任务的功能.服务可以被视为重复使用的执行一个或多个相关任务的代码块. AngularJS服务是单例对象, ...
- C:进制
进制.C语言内存分配 1.对于进制 10进制 (0 - 9)16进制 (0——9 A B C D E F)硬件中的高低电平(0 和 1表示)所以计算机用 二进制 机器语言就是由 0 和 1 组成的一 ...