博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++之萃取技术(traits)
阅读量:7125 次
发布时间: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

你可能感兴趣的文章
GET和POST区别详解
查看>>
java.nio.ByteBuffer中flip、rewind、clear方法的区别
查看>>
秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...
查看>>
PHP LFI to arbitratry code
查看>>
解决tomcat启动超时
查看>>
错误Name node is in safe mode的解决方法
查看>>
小黑小波比.Ubuntu下安装Intellij IDEA和java的环境变量
查看>>
程序员必备:项目时间估算技能
查看>>
Shell编程,read的用法
查看>>
gulp koa nodejs 实现的前段工程分离开发
查看>>
MySQL/HandlerSocket和VoltDB:NoSQL的竞争者
查看>>
Inside AbstractQueuedSynchronizer (2)
查看>>
VC组件之间的通信所需的端口
查看>>
POI操作Excel导入导出
查看>>
MFC edit control 用法
查看>>
Server SSL certificate verification failed: certificate issued for a different hostname, issuer is
查看>>
为什么无法从prototype修改constructor 函数
查看>>
音符频率表
查看>>
Android Activity之间数据的传递
查看>>
sql server 调用系统DOS命令
查看>>