C++_浅析C++标准库元组(tuple)源码,一、什么是元组元组不是什
tuple是个可变参数的类模板:
获取tuple中的值,用std::get。这不是函数,而是函数模板,我们需要传入size_t类型的变量将其特化,或者传入一个类型,告诉它我们需要取出元组中的哪个类型的成员。
3.4 部分成员函数
std::tuple<int, std::string> tu{ 2,"12iop" };
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 }
元组不是什么新鲜东西,在数学、python语言还有我们今天要说的C++都有元组。
这是对类模板的声明。
template<class _This, class... _Rest> class tuple<_This, _Rest...> : private tuple<_Rest...> { // 内容 }
我们通过get<char>的方式得到了s,它是char类型的变量。std::get<T>可以从tuple中获取到第一个类型为T的成员。
tuple<>定义了空的构造函数和拷贝构造函数(空tuple没什么可做的)。
3.3 构造函数
上面的代码中,我用constexpr修饰了t2,这是完全正确的,std::tuple的构造函数是constexpr的。
3.1 tuple<>
template<typename... _Types> class tuple;
_Mybase& _Get_rest() noexcept { return (*this); } constexpr const _Mybase& _Get_rest() const noexcept { return (*this); }
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 }
以上就是C++标准库元组(tuple)源码浅析的全部内容,希望对大家的学习有所帮助。
std::tuple<int, std::string> t5{ 1,"qwer" }; if (t1 == t5) { std::cout << "==" << std::endl; }
其中进行了静态断言,如果两个tuple的元素个数不相同,会引发一个编译时的错误。如果对应的类型不能用==进行比较,在模板特化时也会引发编译期的错误,例如,tuple<std::string, int>不能和tuple<int, char>比较,因为std::string和int是不能用==进行比较的。
赋值符号返回左边的引用,这种行为和C++的内置类型是一致的。_Get_rest是tuple的成员函数,作用是把除了_Myfirst之外的那些元素拿出来。
tuple实际上是一个有可变参数的类模板,使用的时候,传入若干个参数将其特化。
tuple的构造函数没什么可说的,就是初始化_Myfirst和_MyBase,当然,_MyBase也要进行么一个过程,直到tuple<>。
这个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没有基类也不存储任何元素。
tuple重载了赋值符号(=),这样,tuple之间是可以赋值的
那么,tuple是如何存储其中的元素呢?
三、源码分析
成员函数swap用于与另一个tuple<>交换内容,因为没什么可交换的,函数体当然是空的。
介绍tuple的用法不是本文的主要内容,故到此为止。有兴趣的同学可以自行查阅资料。
前面提到的_Get_rest在这里:
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())); }
_Less从函数名看,是为了比较大小,但如果遇到没有重载<的类型呢?暂时不管它。
接下来,是时候考察一看源码了。
它还提供了默认拷贝构造函数和移动构造函数(移动语义是C++11中新增的特性,请自行查阅资料)。其实,它还有很多构造函数,写起来挺热闹,无非就是用不同的方式为它赋初值,故省略。
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”功能,所以,这样的方式可以将不同类型的对象组合在一起。如下图:
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;
简单地说,元组就是一组东西,例如,在讲代数拓扑的时候,经常把拓扑空间X和其中一点x作为一个偶对(X, x),这其实就是个元组,点的坐标也可以看成一个元组。C++中的元组(tuple)是这个样子的:
原来,它有个成员叫_Myfirst,它就是用来存储_This类型的变量的。你会看到_Myfirst的类型不是_This而是_Tuple_val<_This>,其实,_Tuple_val又是一个类模板,它的代码这里就不展开了,简而言之,它的作用是存储一个tuple中的变量。_Myfirst._Val才是真正的元素。
要想使用tuple,要包含头文件<tuple>:
有了空tuple的定义,就可以定义非空的tuple。
_Equals用来判断两个tuple<>是否相等,它返回true,这是显然的(所有的tuple<>都是一个样子)。
接下来,实现参数个数为零的空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; // 存储的元素 }
allocator_arg_t是个空的结构体,暂时不管它。_Myt就是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); }
一个tuple可以包含不同类型的成员,例如上面的tu包含一个int和一个字符串。
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; } };
3.2 非空的tuple
它返回对基类的引用。*this的类型虽然是_Myt,但根据C++语法(可以把派生类的引用赋给对基类的引用),所以这样做是没问题的。
std::get也是constexpr的,所以n2也是一个编译时的常量。
一、什么是元组
二、用法
#include <tuple>
接下来是成员函数_Equals,
在考察源码之前,我们必须先知道它的用法。
相关热词: C++
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://v30.fanwenzhu.com/jiaob/cjj/5589.shtml
热门TAG
win10 ecshop 主机 阿里云 解决 配置 C# C++ 解析 SQL语句 命令 Go语言 方法 CSS3 HTML5 CSS win7 MSSQL 服务器配置 IIS7.5 IIS7 IIS6 IIS CentOS 7 Linux oracle数据库 oracle phpcms discuz discuz教程最新文章
-
只需要在调用Ctrl+B编译后
时间:2021-01-13
-
OpenGL超级宝典visual studio
时间:2021-01-04
-
Directx11 教程(2) 基本的wi
时间:2021-01-04
-
LeetCode11ContainerWithMostWate
时间:2021-01-04
-
C语言简单IT之家速成
时间:2020-12-27
-
三分钟了解Activity工作流
时间:2020-12-27
-
编译器是如何实现32位整型
时间:2020-12-27
-
C++中lower_bound函数和upper
时间:2020-12-27
热门文章
-
LeetCode11ContainerWithMostWater(最大水容器)
时间:2021-01-04
-
C语言简单编程速成
时间:2020-12-23
-
都2020了,这五个最佳C++的IDE你还没用过?
时间:2020-12-23
-
C语言源程序文件的后缀是什么?
时间:2020-12-23
-
OpenGL超级宝典visual studio 2013开发环境配置
时间:2021-01-04
-
编译器是如何实现32位整型的常量整数除
时间:2020-12-27
-
libusbwin32学习笔记(二)
时间:2020-12-27
-
C语言简单IT之家速成
时间:2020-12-27
-
C语言和Python语言有什么区别呢?
时间:2020-12-24
-
C++对象模型之RTTI的实现原理
时间:2020-12-23
