Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >剖析STL源码,明白typename

剖析STL源码,明白typename

作者头像
公众号guangcity
修改于 2020-10-20 14:23:11
修改于 2020-10-20 14:23:11
64100
代码可运行
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)
运行总次数:0
代码可运行

导语

STL底层源码有下面几行,typedef与typename联用,这几个看着好复杂,究竟啥意思,我们今天一起来剖析!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<typename _Iterator>
struct iterator_traits
{
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

typename的常见用法

首先学习一下typename的常见用法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <typename T>
int compare(const T &a, const T &b)
{
    return a>b?a:b;
}

上述只是个案例程序,如果想写的比较完整比较大小,还得考虑特化版本,也许你会想到上面这段代码中的typename换成class也一样可以,不错!那么这里便有了疑问,这两种方式有区别么?查看C++ Primer之后,发现两者完全一样.

类作用域

在类外部访问类中的名称时,可以使用类作用域操作符,形如MyClass::name的调用通常存在三种:静态数据成员、静态成员函数和嵌套类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct MyClass {
    static int A; //静态成员
    static int B(){cout<<"B()"<<endl; return 100;} //静态函数
    typedef int C;  //嵌套类型
    struct A1 { //嵌套类型
        static int s;
    };
};

调用的时候,可以直接调:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cout<<MyClass::A<<endl;
cout<<MyClass::B()<<endl;
MyClass:C c;
...

完整例子尝试

让我们回到一个typename的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <class T>
void foo() {
    T::iterator * iter;
    // ...
}

这段代码的目的是什么?多数人第一反应可能是:作者想定义一个指针iter,它指向的类型是包含在类作用域T中的iterator。可能存在这样一个包含iterator类型的结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct MyIterator {
    struct iterator {

    };
};

调用如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
foo<MyIterator>();

这样一来,iter那行代码就很明显了,它是一个MyIterator::iterator类型的指针。我们猜测是这样的,现实是不是呢?

可是,如果是像T::iterator这样呢?T是模板中的类型参数,它只有等到模板实例化时才会知道是哪种类型,更不用说内部的iterator。通过前面类作用域的介绍,我们可以知道,T::iterator实际上可以是以下三种中的任何一种类型:

  • 静态数据成员
  • 静态成员函数
  • 嵌套类型

前面例子中的ContainsAType::iterator是嵌套类型,完全没有问题。可如果是静态数据成员呢?如果实例化foo模板函数的类型是像这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct MyIterator {
    static int iterator;
};

那么,T::iterator * iter;编译器实例化为MyIterator::iterator * iter;,这是什么?前面是一个静态成员变量而不是类型,那么这便成了一个乘法表达式,只不过iter在这里没有定义,编译器会报错:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
error: no type named ‘iterator’ in ‘struct MyIterator’

typename

对于用于模板定义的依赖于模板参数的名称,只有在实例化的参数中存在这个类型名,或者这个名称前使用了typename关键字来修饰,编译器才会将该名称当成是类型。除了以上这两种情况,绝不会被当成是类型。

因此,如果你想直接告诉编译器T::iterator是类型而不是变量,只需用typename修饰:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <class T>
void foo() {
    typename T::iterator * iter;
}

这样编译器就可以确定T::iterator是一个类型,而不再需要等到实例化时期才能确定,因此消除了前面提到的歧义。

剖析源码

回到STL源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<typename _Iterator>
struct iterator_traits
{
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type        value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer           pointer;
  typedef typename _Iterator::reference         reference;
};

看到上面的,我们就一下子清楚了,无非就是使用typename告诉编译器_Iterator::iterator_category是一个类型,然后使用typedef重命名一下,其余类似!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C++中typename的用法
最近在看STL源码剖析时,遇到关于typename的用法,平常接触到的只是在定义模板参数时使用,直到遇到这个问题我才彻底的查找了typename的用法。先看下一个例子:
狼啸风云
2021/03/23
3.3K0
60秒问答:多态和函数重载的关系?
运行时的多态:通过类继承和虚函数实现的(根据虚表指针 指向 派生类的函数,还是基类的函数)
早起的鸟儿有虫吃
2021/07/22
1.5K0
​C++ STL源码剖析之知其然,知其所以然,源码面前了无秘密!
本节使用上节Traits特性,研究iterator源码,来实现一个简单的iterator_category,同时对iterator的源码结构进行分析。
公众号guangcity
2019/10/14
1.3K0
​C++ STL源码剖析之知其然,知其所以然,源码面前了无秘密!
C++ STL源码剖析之Traits编程技法
在 STL 编程中,容器和算法是独立设计的,即数据结构和算法是独立设计的,连接容器和算法的桥梁就是迭代器了,迭代器使其独立设计成为可能。如下图所示:
公众号guangcity
2019/10/12
1.4K0
C++ STL源码剖析之Traits编程技法
C++学习笔记-迭代器(iterator)与萃取机(traits)
提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露容器的内部表述方式。stl的中心思想就是容器和算法分离,然后用一个胶着剂将它们撮合在一起。下面展示一下应用:比如算法find(),要寻找各种容器里的数据,代码如下:
买唯送忧
2021/05/21
2K0
STL 源码剖析之动态数组 vector
vector 的数据安排以及操作方式,与 array 非常相似。两者的唯一差别在于空间的运用的灵活性,array 是静态的,一旦配置了就不能改变,而 vector 是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。下面一起来看一下 vector 的"内部机制",怎么来实现空间配置策略的。
公众号guangcity
2019/10/15
1.6K0
STL 源码剖析之动态数组 vector
C++箴言:理解typename的两个含义
在c++Template中很多地方都用到了typename与class这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢?       相信学习C++的人对class这个关键字都非常明白,
阳光岛主
2019/02/19
4.8K0
STL源码剖析_stl编程指令详解
STL(Standard Template Library),即标准模板库,是一个高效的C++程序库。包含了诸多在计算机科学领域里常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。其核心思想就是泛化编程(generic programming),在这种思想里,大部分基本算法被抽象,被泛化,独立于与之对应的数据结构,用于以相同或相近的方式处理各种不同情形。
全栈程序员站长
2022/09/20
7160
STL源码剖析_stl编程指令详解
C++11 为自定义容器实现标准的forward迭代器
当前我的一个项目是基于C++11为基础开发的,在项目中需要用到哈希表来保持数据,C++11本身已经提供了丰富的容器类型(array,list,hashmap….vector),但因为项目的特殊需要不能使用C++11现成的unordered_map容器。无奈所以我只能自己根据项目需要写了一个哈希表的模板类–HashTableAbstract–也就是自定义容器。 然后问题了,为了让这个自定义的容器也能像unordered_map一样使用forward(向前)迭代器进行遍历数据,还要为它实现一个forward迭代器。下面以此为例来简要说明为自定义的容器实现标准的迭代器的办法。
10km
2022/05/07
5240
C++ STL空间配置源码分析以及实现二
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haluoluo211/article/details/80573204
bear_fish
2018/09/14
6700
C++ STL空间配置源码分析以及实现二
C++ typename的双重含义
这两种写法并没有任何区别,都是标记T是模板类型参数,可以是任何类型,包括用户自定义类型或是语言的基本类型。虽然而这在用于模板类型参数申明时的作用完全相同,但是仍建议使用typename,因为typename的字面意义即表示类型名称,更加符合其语义。而class则多用于类的申明,而非模板类型参数。当然,如果原有项目中均使用class,那么请与原有项目风格保持一致。
恋喵大鲤鱼
2018/09/27
1.3K0
C++ 模板元编程简介
模板元编程(Template Metaprogramming,TMP)是编写生成或操纵程序的程序,也是一种复杂且功能强大的编程范式(Programming Paradigm)。C++模板给C++提供了元编程的能力,但大部分用户对 C++ 模板的使用并不是很频繁,大致限于泛型编程,在一些系统级的代码,尤其是对通用性、性能要求极高的基础库(如 STL、Boost)几乎不可避免在大量地使用 C++ 模板以及模板元编程。
恋喵大鲤鱼
2018/09/27
7K0
C++ 模板元编程简介
C++ STL源码剖析 tr1与std array
C++ tr1全称Technical Report 1,是针对C++标准库的第一次扩展。即将到来的下一个版本的C++标准c++0x会包括它,以及一些语言本身的扩充。tr1包括大家期待已久的smart pointer,正则表达式以及其他一些支持范型编程的内容。草案阶段,新增的类和模板的名字空间是std::tr1。
公众号guangcity
2019/10/15
1.2K0
C++ STL源码剖析 tr1与std array
发布一个STL源码剖析专栏及序列式容器deque
大家好,我是光城,最近一直在研究STL源码剖析,据此,开一个知乎专栏:《C++ STL 源码剖析》,地址戳下面或点击阅读原文,欢迎大家关注!
公众号guangcity
2019/10/20
9090
C++(STL):31 ---关联式容器map源码剖析
map的特性 所有元素都会根据元素的键值自动被排序 map中的pair结构 map的所有元素类型都是pair,同时拥有实值(value)和键值(key) pair的第一个元素视为键值,第二个元素视为实值 map不允许两个元素拥有相同的键值 下面是stl_pair.h中pair的定义: //代码摘录与stl_pair.h template <class _T1, class _T2> struct pair { typedef _T1 first_type; typedef _T2 second_type;
用户3479834
2021/02/03
1.7K0
C++(STL):31 ---关联式容器map源码剖析
从零开始学C++之STL(三):迭代器类vector::iterator 和 vector::reverse_iterator 的实现、迭代器类型、常用的容器成员
一、迭代器 迭代器是泛型指针 普通指针可以指向内存中的一个地址 迭代器可以指向容器中的一个位置 STL的每一个容器类模版中,都定义了一组对应的迭代器类。使用迭代器,算法函数可以访问容器中指
s1mba
2017/12/28
2.4K0
从零开始学C++之STL(三):迭代器类vector::iterator 和 vector::reverse_iterator 的实现、迭代器类型、常用的容器成员
浅谈如何实现自定义的 iterator 之二
我打算实现一个简单而又不简单的树容器,让它成为标准的文件目录结构式的容器类型。但简单就在于,我只准备实现最最必要的几个树结构的接口,诸如遍历啦什么的。
玖柒的小窝
2021/10/31
6280
g ++在linux下编译rapidxml 使用与过程中出现的问题解决[通俗易懂]
1:修改rapidxml_iterators.hpp文件 第20 和 102 行
全栈程序员站长
2022/09/13
8400
g ++在linux下编译rapidxml 使用与过程中出现的问题解决[通俗易懂]
10.1 C++ STL 模板适配与迭代器
STL(Standard Template Library)标准模板库提供了模板适配器和迭代器等重要概念,为开发者提供了高效、灵活和方便的编程工具。模板适配器是指一组模板类或函数,它们提供一种适配机制,使得现有的模板能够适应新的需求。而迭代器则是STL中的令一种重要的概念,它是一个抽象化的数据访问机制,通过迭代器可以遍历STL容器中的元素。适配器与迭代器两者的紧密配合,使得开发者能够高效地处理容器中的元素,提高了代码的复用性和可维护性。
王瑞MVP
2023/08/17
2240
C++(STL):33---hash_set、hash_map、hash_multiset、hash_multimap源码剖析
这些关联容器底层都是使用hash table实现的. 一、hash_set 由于hash_set底层是以hash table实现的,因此hash_set只是简单的调用hash table的方法即可 与set的异同点: hash_set与set都是用来快速查找元素的 但是set会对元素自动排序,而hash_set没有 hash_set和set的使用方法相同 在介绍hash table的hash functions的时候说过,hash table有一些无法处理的类型(除非用户自己书写hash function
用户3479834
2021/02/03
2.1K0
C++(STL):33---hash_set、hash_map、hash_multiset、hash_multimap源码剖析
推荐阅读
相关推荐
C++中typename的用法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验