C++ 模板类型萃取技术 第二部分 基于泛型的类型萃取技术

2024-03-07 18:38

本文主要是介绍C++ 模板类型萃取技术 第二部分 基于泛型的类型萃取技术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

总结一下,我们之所以要萃取迭代器相关的类型,无非是要把迭代器相关的类型用于声明局部变量、用作函数的返回值等一系列行为。对于原生指针和point-to-const类型的指针,采用模板偏特化技术对其进行特殊处理,另外,对于point-to-const类型的指针,为了保证声明左值时语义正确,特化时按照普通原生指针处理。<?xml:namespace prefix = o />

实际上,把我们刚才的例子提炼一下,迭代器相应类型不仅仅有迭代器封装的对象类型,STL中对这些类型作了整理,有如下几种:

template <class I>

struct iterator_traits {

    typedef typename I::iterator_category iterator_category;

    typedef typename I::value_type value_type;

    typedef typename I::difference_type difference_type;

    typedef typename I::pointer pointer;

    typedef typename I::reference reference;

}

当然,也如你所想,对于原生pointer和pointer-to-const这两种情况,STL分别对其进行了特化处理。如果你看了上面的代码却不知所云,也属正常,在去了解特化版本之前,我们先来看看这五种类型的含义。

Type 1 value_type

这个类型和我们在第一部分谈到的vlaue_type的含义是一样的,不多说了。

Type 2 difference_type

用来表示两个迭代器之间的最大距离。这个类型用来对某种算法提供计数功能,例如:

template <class I, class T>

typename iterator_traits<I>::difference_type

count(I first, I last, const T& value){

    typename iterator_traits<I>::difference_type n = 0;

    for(; first != last; first++) {

        if(*first == value)

            n++;

}

return n;

}

也许这个例子最足以说明问题,任何的解释都没必要了。这里需要说明的是。对于原生指针,由于不存在int::difference_type的情况,所以,iterator_traits对其进行特化:

template <class I>

class iterator_traits<I*> {

    typedef ptrdiff_t difference_type;

}

这里,ptrdiff_t是定义在cstddef中的一个C++内置类型,在GNU gcc中,定义如下:

typedef long int ptrdiff_t;

同样,对于pointer-to-const,也要入法炮制:

template <class I>

class iterator_traits<const I*> {

    typedef ptrdiff_t difference_type;

}

再一次,偏特化技术帮了大忙,现在count可以处理所有类型迭代器的difference_type了。

Type 3 reference

这里,reference type指的是迭代器封装对象的类型的引用。这个类型的出现主要是为了解决对指针进行解引用的时候,返回什么样的对象的问题。我们希望:

 MyIter<int> iter(new int(10));

*iter = 52;

Int *p = new int(10);

*p = 52;

是一样的。于是,reference_type一般用在迭代器的*运算符重载上,让所有的“指针家族”有同样的表现形式。于是,如果value_type是T,那么reference_type就是T&,如果value_type是const T,reference_type就是const T&。

Type 4 pointer

C++中指针和引用总是有着密切的关系。如果我们想返回迭代器封装的对象的地址,就需要用到这里的pointer_type,主要用在迭代器中对->运算符重载的问题。对于一个智能指针来说,通常我们都需要下面的两个运算符重载:

T& operator*() const { return *ptr; } // T& is reference type

T* operator->() const { return ptr; } // T* is pointer type

同样,为了能够对迭代器和原生指针都能够在算法上有统一的表现形式,在iterator_traits中加入了下面的类型

template <class T>

struct iterator_traits {

    typedef typename I::pointer pointer;

    typedef typename I::reference reference;

}

同样,对于原生指针和point-to-const类型的指针作了特化:

template<class T>

struct iterator_traits<T*> {

    typedef typename T* pointer;

    typedef typename T& reference;

}

而这次,对于point-to-const类型的指针,则有些特别:

template<class T>

struct iterator_traits<const T*> {

    typedef typename const T* pointer;

    typedef typename const T& reference;

}

也就是说,当我们解引用一个封装了常量对象的迭代器的时候,返回的类型应该是const T&,取一个封装了常量对对象的迭代器中的元素的地址,返回的应该是const T*。最终的结果,就是所有的算法都有了一个统一的表达方式:

template <class T>

typename iterator_traits<T>::reference func() {}

template <class T>

typename iterator_traits<T>::pointer func() {}

Type 5 iterator_category

这个类型的作用是按照迭代器的移动特性和能够在该迭代器上实施的操作对迭代器进行分类,之所以这样做,完全是为了效率的考量。不过,在我看来,对其分类的因素实际上只有迭代器的移动特性,而分类,也非常简单:一步步向前挪的类型和一步跨到位的类型。

这篇关于C++ 模板类型萃取技术 第二部分 基于泛型的类型萃取技术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/784450

相关文章

闲置电脑也能活出第二春?鲁大师AiNAS让你动动手指就能轻松部署

对于大多数人而言,在这个“数据爆炸”的时代或多或少都遇到过存储告急的情况,这使得“存储焦虑”不再是个别现象,而将会是随着软件的不断臃肿而越来越普遍的情况。从不少手机厂商都开始将存储上限提升至1TB可以见得,我们似乎正处在互联网信息飞速增长的阶段,对于存储的需求也将会不断扩大。对于苹果用户而言,这一问题愈发严峻,毕竟512GB和1TB版本的iPhone可不是人人都消费得起的,因此成熟的外置存储方案开

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

离心萃取机废旧磷酸铁锂电池回收工艺流程

在废旧磷酸铁锂电池的回收工艺流程中,离心萃取机主要应用于萃取除杂的步骤,以提高回收过程中有价金属(如锂)的纯度。以下是结合离心萃取机应用的废旧磷酸铁锂电池回收工艺流程: 电池拆解与预处理 拆解:将废旧磷酸铁锂电池进行拆解,分离出电池壳、正负极片、隔膜等部分。破碎与筛分:将正负极片进行破碎处理,并通过筛分将不同粒径的物料分开,以便后续处理。 浸出与溶解 浸出:采用适当的浸出工艺(如二段式逆

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]