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++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C