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

相关文章

C# Where 泛型约束的实现

《C#Where泛型约束的实现》本文主要介绍了C#Where泛型约束的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用的对象约束分类where T : structwhere T : classwhere T : ne

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

IDEA自动生成注释模板的配置教程

《IDEA自动生成注释模板的配置教程》本文介绍了如何在IntelliJIDEA中配置类和方法的注释模板,包括自动生成项目名称、包名、日期和时间等内容,以及如何定制参数和返回值的注释格式,需要的朋友可以... 目录项目场景配置方法类注释模板定义类开头的注释步骤类注释效果方法注释模板定义方法开头的注释步骤方法注

一文详解如何在Python中从字符串中提取部分内容

《一文详解如何在Python中从字符串中提取部分内容》:本文主要介绍如何在Python中从字符串中提取部分内容的相关资料,包括使用正则表达式、Pyparsing库、AST(抽象语法树)、字符串操作... 目录前言解决方案方法一:使用正则表达式方法二:使用 Pyparsing方法三:使用 AST方法四:使用字

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下: