博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++之萃取技术(traits)
阅读量:7070 次
发布时间:2019-06-28

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

为什么需要类型萃取(特化)

前面我们提到了迭代器,它是一个行为类似于smart pointer之类的东西,主要用于对STL容器中的对象进行访问,而且不暴露容器中的内部结构,而迭代器所指对象的型别称为该迭代器的value type;如果在实际的工程当中我们应该怎么获取STL容器中对象的value type 呢,这里面就需要用到C++中模板的特化了,我们先来看看下面的代码:

template 
void Func(){ cout << "非内置类型" << endl;}template <>void Func
() { cout << "内置的int类型" << endl;}

   

我们可以通过特化来推导参数,如果我们自定义了多个类型,除非我们把这些自定义类型的特化版本写出来,否则我们只能判断他们是内置类型,并不能判断他们具体属于是个类型。

这时候,我们引入了内嵌型别,在类中将迭代器所指向的类型定义成value type,还定义些其他的型别,具体的见前面博客中所提到的迭代器的内嵌型别,迭代器:

typedef bidirectional_iterator_tag    iterator_category;  typedef T value_type;  typedef Ptr pointer;  typedef Ref reference;  typedef __list_node
* link_type; typedef size_t size_type; typedef ptrdiff_t difference_type;

    

但是这种情况还是有缺口的,例如下面的代码:

template 
struct MyIter{ typedef T ValueType; T* _ptr; MyIter(T* p = 0) :_ptr(p) {} T& operator*() { return *_ptr; }};template
typename Iterator::ValueTypeFunc(Iterator it){ return *it;}

   

这里虽然看上去没有什么问题,但并不是所有的迭代器都有内嵌型别的,例如原生指针,因为原生指针不是类型别,所以我们无法为原生指针定义内嵌型别。

我们还可以看看下面这个例子:

这里先给出代码:

//Vector的代码template 
class Vector{public: //vector的内嵌型别 typedef T ValueType; typedef ValueType* Pointer; typedef const ValueType* ConstPointer; typedef ValueType* Iterator; typedef const ValueType* ConstIterator; typedef const ValueType* ConstPointer; typedef ValueType& Reference; typedef const ValueType& ConstReference; typedef size_t SizeType; typedef size_t DifferenceType;public: Vector() : _start(0) , _finish(0) , _EndOfStorage(0) {} //Vector() Iterator Begin() { return _start; } Iterator End() { return _finish; } ConstIterator cBegin() const { return _start; } ConstIterator cEnd() const { return _finish; } ValueType& operator[](const SizeType& n) { return *(_start + n); } //Const ValueType& operator[](const SizeType& n) const //{ // return *(_start + n); //} void PushBack(const ValueType& x) { //扩容 _CheckCapacity(); Insert(_finish, x); } void Insert(Iterator pos,const ValueType& x) { //SizeType n = pos - _begin; //assert(pos>=_start&&pos<=_finish); if (pos == _finish) { Construct(_finish, x); _finish++; } else { //计算插入点之后的现有元素的个数 size_t ElemFront = _finish - pos; /* _finish++;*/ for (int i = 0; i < ElemFront; i++) { Iterator CopyPos = _finish - i; Construct(CopyPos, *(CopyPos - 1)); } _finish++; Construct(pos, x); } }protected: typedef SimpleAlloc
DataAllocator; Iterator _start; Iterator _finish; Iterator _EndOfStorage;protected: void _CheckCapacity() { if (_finish == _EndOfStorage) { //空间已满,开辟空间 size_t OldSize = _finish - _start; size_t NewSize = OldSize * 2 + 3; T* _tmp = DataAllocator::allocate(NewSize); //开辟新的空间 for (size_t i = 0; i < OldSize; i++) { //拷贝原数组当中的成员 _tmp[i] = _start[i]; } //改变参数 swap(_start, _tmp); _finish = _start + OldSize; _EndOfStorage = _start + NewSize; //释放空间 DataAllocator::deallocate(_tmp, OldSize); } }};void TestVector(){ Vector
v1; v1.PushBack(1); v1.PushBack(2); v1.PushBack(3); v1.PushBack(4); v1.PushBack(5); v1.PushBack(6); Vector
::Iterator it =v1.Begin(); while (it != v1.End()) { cout << *it << " "; it++; } cout << "Distance?" << Distance(v1.Begin(), v1.End()) << endl;} //求两个迭代器之间距离的函数//普通类型的求两个迭代器之间距离的函数template
inline size_t __Distance(InputIterator first, InputIterator last, InputIteratorTag) { size_t n = 0; while (first != last) { ++first; ++n; } return n;}//RandomAccessIteratorTag类型的求两个迭代器之间距离的函数template
inline size_t __Distance(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIteratorTag){ size_t n = 0; n += last - first; return n;}//求两个迭代器之间的距离的函数template
inline size_t Distance(InputIterator first, InputIterator last) { return __Distance(first, last,InputIterator::IteratorCategory()); /*return __Distance(first, last,IteratorTraits
::IteratorCategory()); */}

   

如果只有内嵌型别,会发生下面的情况: 

这里图中已经给出了详细的解释。

原生指针本来应该是迭代器当中的RandomAccessIterator,这里因为无法为原生指针定义类型,所以我们就没有办法拿到原生指针的迭代器,这时候,类型萃取就出来了:

//类型萃取template 
struct IteratorTraits{ typedef typename Iterator::IteratorCategory IteratorCategory; typedef typename Iterator::ValueType ValueType; typedef typename Iterator::DifferenceType DifferenceType; typedef typename Iterator::Pointer Pointer; typedef typename Iterator::Reference Reference;};//原生指针的类型萃取template
struct IteratorTraits
{ typedef RandomAccessIteratorTag IteratorCategory; typedef T ValueType; typedef ptrdiff_t DifferenceType; typedef T* Pointer; typedef T& Reference;};//针对const T*的类型萃取template
struct IteratorTraits
{ typedef RandomAccessIteratorTag IteratorCategory; typedef T ValueType; typedef ptrdiff_t DifferenceType; typedef T* Pointer; typedef T& Reference;};

   

这时候,我们就能调用正确的__Distance函数了。 

 

类型萃取的设计模式提高了代码的复用性,在上面的例子中通过萃取出不同的迭代器的类型来调用不同迭代器的__Distance函数,也提升了代码的性能。

参考:http://www.cnitblog.com/weitom1982/archive/2008/12/19/7889.html 

 

转载于:https://www.cnblogs.com/cthon/p/9206281.html

你可能感兴趣的文章
大家好,今天入住51CTO博客
查看>>
Bat 命令使用
查看>>
dmidecode 查看硬件详细信息
查看>>
elasticsearch 常用管理命令
查看>>
VMware vSphere 4.1虚拟化学习手册11:使用Converter工具V2V、P2V导入虚拟机
查看>>
我的友情链接
查看>>
python 正则表达式 笔记
查看>>
possible SYN flooding on port 80. Sending cookies
查看>>
联想天工ispirit 4505核心交换机配置笔记
查看>>
【CISCO技术】GRE-虚拟专用网络(静态)
查看>>
用mysql自带工具mysqlslap对数据库进行压力测试
查看>>
js 浏览器和pc 客户端判断
查看>>
评《GIT和SVN之间的五个基本区别》
查看>>
我的友情链接
查看>>
SEO的核心思想
查看>>
泛域名Wildcard Domain
查看>>
PHP基于FastCGI模式与httpd通信
查看>>
Spring对于注解的扫描
查看>>
微软自带的ftp和web服务器的搭建
查看>>
VS2008 程序简单打包
查看>>