• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 浅析C++标准库元组(tuple)源码

浅析C++标准库元组(tuple)源码

作者:独立风华 字体:[增加 减小] 来源:互联网 时间:2017-05-28

独立风华 通过本文主要向大家介绍了tuple,python tuple,tuple是什么意思,c tuple,tuple类型等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

一、什么是元组

元组不是什么新鲜东西,在数学、python语言还有我们今天要说的C++都有元组。

简单地说,元组就是一组东西,例如,在讲代数拓扑的时候,经常把拓扑空间X和其中一点x作为一个偶对(X, x),这其实就是个元组,点的坐标也可以看成一个元组。C++中的元组(tuple)是这个样子的:

std::tuple<int, std::string> tu{ 2,"12iop" };
</div>

一个tuple可以包含不同类型的成员,例如上面的tu包含一个int和一个字符串。

二、用法

在考察源码之前,我们必须先知道它的用法。

要想使用tuple,要包含头文件<tuple>:

#include <tuple>
</div>

tuple实际上是一个有可变参数的类模板,使用的时候,传入若干个参数将其特化。

struct Point
{
 int x;
 int y;
};
 
void main()
{
 std::tuple<int, std::string> t1{ 1,"qwer" }; // 一个由int和字符串组成的tuple
 constexpr std::tuple<int, void*> t2{ 1,nullptr }; // 一个由int和void*组成的tuple
 std::tuple<int, Point> t3{ 1,{20,89} }; // 一个由int和Point结构体组成的tuple
 std::tuple<int, char, std::string> t4{ 1,'t',"qwer" }; // 一个由int、char、字符串组成的tuple
}
</div>

上面的代码中,我用constexpr修饰了t2,这是完全正确的,std::tuple的构造函数是constexpr的。

获取tuple中的值,用std::get。这不是函数,而是函数模板,我们需要传入size_t类型的变量将其特化,或者传入一个类型,告诉它我们需要取出元组中的哪个类型的成员。

struct Point
{
 int x;
 int y;
};
 
void main()
{
 std::tuple<int, std::string> t1{ 1,"qwer" };
 constexpr std::tuple<int, void*> t2{ 10,nullptr };
 std::tuple<int, Point> t3{ 1,{20,89} };
 std::tuple<int, char, std::string> t4{ 1,'t',"qwer" };
 
 std::cout << std::get<0>(t1) << std::endl; // 1
 
 constexpr int n2 = std::get<0>(t2);
 std::cout << n2 << std::endl; // 10
 
 auto s = std::get<char>(t4);
 std::cout << s << std::endl; // t
}
</div>

std::get也是constexpr的,所以n2也是一个编译时的常量。

我们通过get<char>的方式得到了s,它是char类型的变量。std::get<T>可以从tuple中获取到第一个类型为T的成员。

tuple也可以用【==】和【!=】比较是否相等:

std::tuple<int, std::string> t5{ 1,"qwer" };
 
if (t1 == t5)
{
 std::cout << "==" << std::endl;
}
</div>

介绍tuple的用法不是本文的主要内容,故到此为止。有兴趣的同学可以自行查阅资料。

接下来,是时候考察一看源码了。

三、源码分析

tuple是个可变参数的类模板:

template<typename... _Types>
class tuple;
</div>

这是对类模板的声明。

接下来,实现参数个数为零的空tuple。

3.1 tuple<>

struct allocator_arg_t
{};
 
template<>
class tuple<>
{
public:
 typedef tuple<> _Myt;
 
 constexpr tuple() noexcept
 {}
 
 template<typename _Alloc>
 tuple(allocator_arg_t, const _Alloc&) noexcept
 {}
 
 constexpr tuple(const tuple&) noexcept
 {}
 
 template<class _Alloc>
 tuple(allocator_arg_t, const _Alloc&, const _Myt&) noexcept
 {}
 
 void swap(_Myt&) noexcept
 {}
 
 constexpr bool _Equals(const _Myt&) const noexcept
 {
 return true;
 }
 
 constexpr bool _Less(const _Myt&) const noexcept
 {
 return false;
 }
};
</div>

allocator_arg_t是个空的结构体,暂时不管它。_Myt就是tuple<>自己,这样写起来方便一些。

tuple<>定义了空的构造函数和拷贝构造函数(空tuple没什么可做的)。

成员函数swap用于与另一个tuple<>交换内容,因为没什么可交换的,函数体当然是空的。

_Equals用来判断两个tuple<>是否相等,它返回true,这是显然的(所有的tuple<>都是一个样子)。

_Less从函数名看,是为了比较大小,但如果遇到没有重载<的类型呢?暂时不管它。

有了空tuple的定义,就可以定义非空的tuple。

3.2 非空的tuple

template<class _This,
class... _Rest>
class tuple<_This, _Rest...>
 : private tuple<_Rest...>
{
 // 内容
}
</div>

n(>0)个元素的tuple私有继承了n-1个元素的tuple。显然这是一种递归定义,最终会递归到tuple<>,而tuple<>是已经定义好了得。

例如,tuple<int, char, short>私有继承了tuple<char, short>,而tuple<char, short>又私有继承了tuple<short>,tuple<short>私有继承了tuple<>。由于私有继承可以实现“has-a”功能,所以,这样的方式可以将不同类型的对象组合在一起。如下图:

那么,tuple是如何存储其中的元素呢?

template<class _This,
class... _Rest>
class tuple<_This, _Rest...>
 : private tuple<_Rest...>
{ // recursive tuple definition
public:
 typedef _This _This_type;
 typedef tuple<_This, _Rest...> _Myt;
 typedef tuple<_Rest...> _Mybase;
 static const size_t _Mysize = 1 + sizeof...(_Rest);
 
 _Tuple_val<_This> _Myfirst; // 存储的元素
}
</div>

原来,它有个成员叫_Myfirst,它就是用来存储_This类型的变量的。你会看到_Myfirst的类型不是_This而是_Tuple_val<_This>,其实,_Tuple_val又是一个类模板,它的代码这里就不展开了,简而言之,它的作用是存储一个tuple中的变量。_Myfirst._Val才是真正的元素。

这个tuple只存储一个元素,类型为_Rest...的其他元素存在基类_MyBase即tuple<_Rest...>中。我们仍然以tuple<int, char, short>为例,tuple<int, char, short>存储了一个int,有基类tuple<char, short>;而tuple<char, short>存储了一个char,有基类tuple<short>;tuple<short>存储了一个short,有基类tuple<>;tuple没有基类也不存储任何元素。

3.3 构造函数

tuple的构造函数没什么可说的,就是初始化_Myfirst和_MyBase,当然,_MyBase也要进行么一个过程,直到tuple<>。

 constexpr tuple(): _Mybase(), _Myfirst()
 {}
 
 constexpr explicit tuple(const _This& _This_arg,
 const _Rest&... _Rest_arg)
 : _Mybase(_Rest_arg...),
 _Myfirst(_This_arg)
 {}
 
 tuple(const _Myt&) = default;
 tuple(_Myt&&) = default;
</div>

它还提供了默认拷贝构造函数和移动构造函数(移动语义是C++11中新增的特性,请自行查阅资料)。其实,它还有很多构造函数,写起来挺热闹,无非就是用不同的方式为它赋初值,故省略。

3.4 部分成员函数

tuple重载了赋值符号(=),这样,tuple之间是可以赋值的

 template<class... _Other>
 _Myt& operator=(const tuple<_Other...>& _Right)
 { // assign by copying same size tuple
 _Myfirst._Val = _Right._Myfirst._Val;
 _Get_rest() = _Right._Get_rest();
 return (*this);
 }
</div>

赋值符号返回左边的引用,这种行为和C++的内置类型是一致的。_Get_rest是tuple的成员函数,作用是把除了_Myfirst之外的那些元素拿出来。

接下来是成员函数_Equals,

template<class... _Other>
constexpr bool _Equals(const tuple<_Other...>& _Right) const
{
 static_assert(_Mysize == sizeof...(_Other), "comparing tuple to object with different size");
 return (_Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest()));
}
</div>

其中进行了静态断言,如果

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 浅析C++标准库元组(tuple)源码

相关文章

  • 2017-05-28解析C++ 浮点数的格式化显示
  • 2022-04-30C语言加减乘除运算
  • 2017-05-28C语言/C++如何生成随机数
  • 2017-05-28详解C++编程中类的声明和对象成员的引用
  • 2017-05-28线程池的原理与实现详解
  • 2017-05-28c病毒程序原理分析(防范病毒 c语言小病毒示例)
  • 2017-05-28基于C语言字符串函数的一些使用心得
  • 2017-05-28C++中的delete不会将操作数置0
  • 2017-05-28C++详解默认参数的构造函数及简单实例代码
  • 2017-05-28详解设计模式中的中介者模式在C++编程中的运用

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • c语言多进程tcp服务器示例
    • C语言实现大数据文件的内存映射机制
    • C语言 变量详解及示例代码
    • C++中的三种继承public,protected,private详细解析
    • VC对自定义资源加密解密(AES)的详解
    • 全局变量与局部变量在内存中的区别详细解析
    • 基于Windows API分解路径问题的详解
    • C语言实现奇数阶魔方阵的方法
    • C语言安全编码之数值中的sizeof操作符
    • C程序读取键盘码的方法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有