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

相关文章

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

基于Java实现模板填充Word

《基于Java实现模板填充Word》这篇文章主要为大家详细介绍了如何用Java实现按产品经理提供的Word模板填充数据,并以word或pdf形式导出,有需要的小伙伴可以参考一下... Java实现按模板填充wor编程d本文讲解的需求是:我们需要把数据库中的某些数据按照 产品经理提供的 word模板,把数据

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

Python中异常类型ValueError使用方法与场景

《Python中异常类型ValueError使用方法与场景》:本文主要介绍Python中的ValueError异常类型,它在处理不合适的值时抛出,并提供如何有效使用ValueError的建议,文中... 目录前言什么是 ValueError?什么时候会用到 ValueError?场景 1: 转换数据类型场景

C# dynamic类型使用详解

《C#dynamic类型使用详解》C#中的dynamic类型允许在运行时确定对象的类型和成员,跳过编译时类型检查,适用于处理未知类型的对象或与动态语言互操作,dynamic支持动态成员解析、添加和删... 目录简介dynamic 的定义dynamic 的使用动态类型赋值访问成员动态方法调用dynamic 的

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字