tuple基本用法

news2024/11/19 2:26:11

元组简介

C++11 标准新引入了一种类模板,命名为 tuple(中文可直译为元组)。tuple 最大的特点是:实例化的对象可以存储任意数量、任意类型的数据。

tuple 的应用场景很广泛,例如当需要存储多个不同类型的元素时,可以使用 tuple;当函数需要返回多个数据时,可以将这些数据存储在 tuple 中,函数只需返回一个 tuple 对象即可。

tuple对象的创建

tuple 本质是一个以可变模板参数定义的类模板,它定义在 头文件并位于 std 命名空间中。因此要想使用 tuple 类模板,程序中需要首先引入以下代码:

#include <tuple>
using std::tuple;

实例化 tuple 模板类对象常用的方法有两种,一种是借助该类的构造函数,另一种是借助 make_tuple() 函数。

类的构造函数

1) 默认构造函数
   constexpr tuple();

2) 拷贝构造函数
   tuple (const tuple& tpl);

3) 移动构造函数
   tuple (tuple&& tpl);

4) 隐式类型转换构造函数
   template <class... UTypes>
       tuple (const tuple<UTypes...>& tpl); //左值方式
   template <class... UTypes>
       tuple (tuple<UTypes...>&& tpl);      //右值方式

5) 支持初始化列表的构造函数
   explicit tuple (const Types&... elems);  //左值方式
   template <class... UTypes>
       explicit tuple (UTypes&&... elems);  //右值方式

6) 将pair对象转换为tuple对象
   template <class U1, class U2>
       tuple (const pair<U1,U2>& pr);       //左值方式
   template <class U1, class U2>
       tuple (pair<U1,U2>&& pr);            //右值方式

make_tuple()函数
上面程序中,我们已经用到了 make_tuple() 函数,它以模板的形式定义在 <tuple> 头文件中,功能是创建一个 tuple 右值对象(或者临时对象)。

对于 make_tuple() 函数创建了 tuple 对象,我们可以上面程序中那样作为移动构造函数的参数,也可以这样用:

auto first = std::make_tuple (10,'a');   // tuple < int, char >
const int a = 0; int b[3];
auto second = std::make_tuple (a,b);     // tuple < int, int* >

程序中分别创建了 first 和 second 两个 tuple 对象,它们的类型可以直接用 auto 表示。

创建一个空的元组, 创建时,需要指定元组的数据类型

std::tuple<int, float, double, long, long long> first;

创建一个元组并初始化元组

std::string str_second_1("_1");
std::string str_second_2("_2");

// 指定了元素类型为引用 和 std::string, 下面两种方式都是可以的,只不过第二个参数不同而已
std::tuple<std::string, std::string> second_1(str_second_1, std::string("_2"));
std::tuple<std::string, std::string> second_2(str_second_1, str_second_2);

创建一个元素是引用的元组

//3、创建一个元组,元组的元素可以被引用, 这里以 int 为例
int i_third = 3;
std::tuple<int&> third(std::ref(i_third));

使用make_tuple创建元组

int i_fourth_1 = 4;
int i_fourth_2 = 44;
// 下面的两种方式都可以
std::tuple<int, int> forth_1 = std::make_tuple(i_fourth_1, i_fourth_2);
auto forth_2 = std::make_tuple(i_fourth_1, i_fourth_2);

创建一个类型为引用的元组, 对元组的修改。 这里以 std::string为例

std::string str_five_1("five_1");
// 输出原址值
std::cout << "str_five_1 = " << str_five_1.c_str() << "\n";

std::tuple<std::string&, int> five(str_five_1, 5);
// 通过元组 对第一个元素的修改,str_five_1的值也会跟着修改,因为元组的第一个元素类型为引用。
// 使用get访问元组的第一个元素
std::get<0>(five) = "five_2";

// 输出的将是: five_2
std::cout << "str_five_1 = " << str_five_1.c_str() << "\n";

计算元组的元素个数

需要函数: std::tuple_size。 下面是一个例子

std::tuple<char, int, long, std::string> first('A', 2, 3, "4");
// 使用std::tuple_size计算元组个数
int i_count = std::tuple_size<decltype(first)>::value;
std::cout << "元组个数=" << i_count << "\n";  //4个

访问元素

访问元组的元素,需要函数: std::get<index>(obj)。其中:[index]是元组中元素的下标,0,1,2,3,4,… [obj]-元组变量。

std::tuple<char, int, long, std::string> second('A', 2, 3, "4");
int index = 0;
std::cout << index++ << " = " << std::get<0>(second) << "\n";  //0=A
std::cout << index++ << " = " << std::get<1>(second) << "\n";  //1=2
std::cout << index++ << " = " << std::get<2>(second) << "\n";  //2=3
std::cout << index++ << " = " << std::get<3>(second).c_str() << "\n"; //3=4

元组不支持迭代访问,且只能通过索引(或者tie解包:将元组的中每一个元素提取到指定变量中)访问,且索引不能动态传入。上面的代码中,索引都是在编译器编译期间就确定了。下面的演示代码将会在编译期间出错。

for (int i = 0; i < 3; i++)
       std::cout << index++ << " = " << std::get<i>(second) << "\n";  // 无法通过编译

获取元素的类型

获取元组中某个元素的数据类型,需要用到另外一个类型:std::tuple_element 。 语法:std::tuple_element<index, tuple> 。 [index]-元组中元素的索引,[tuple]哪一个元组。

std::tuple<int, std::string> third(9, std::string("ABC"));

// 得到元组第1个元素的类型,用元组第一个元素的类型声明一个变量
std::tuple_element<1, decltype(third)>::type val_1;

// 获取元组的第一个元素的值
val_1 = std::get<1>(third);
std::cout << "val_1 = " << val_1.c_str() << "\n"; //val_1 = ABC

使用 std::tie解包

元组,可以看作一个包,类比结构体。 需要访问元组的元素时,2 种方法: A、索引访问,B、std::tie。

元组包含一个或者多个元素,使用std::tie解包:首先需要定义对应元素的变量,再使用tie。 比如,元素第0个元素的类型时 char,第1个元素类型时int,那么,需要定义一个 char的变量和int的变量,用来储存解包元素的结果。

std::tuple<char, int, long, std::string> fourth('A', 2, 3, "4");
 
// 定义变量,保存解包结果
char tuple_0 = '0';
int tuple_1 = 0;
long tuple_2 = 0;
std::string tuple_3("");
 
// 使用std::tie, 依次传入对应的解包变量
std::tie(tuple_0, tuple_1, tuple_2, tuple_3) = fourth;

// 输出解包结果
std::cout << "tuple_0 = " << tuple_0 << "\n"; //tuple_0 = A
std::cout << "tuple_1 = " << tuple_1 << "\n"; //tuple_1 = 2
std::cout << "tuple_2 = " << tuple_2 << "\n"; //tuple_2 = 3
std::cout << "tuple_3 = " << tuple_3.c_str() << "\n"; //tuple_3 = 4

std::tie的结构定义如下:

template<class... _Types> inline
    constexpr tuple<_Types&...>
        tie(_Types&... _Args) _NOEXCEPT
{    // make tuple from elements
    typedef tuple<_Types&...> _Ttype;
    return (_Ttype(_Args...));
}

接着 std::tie 解包。 如果一个元组,只需要取出其中特定位置上的元素,不用把每一个元素取出来。比如:只要索引为偶数的元素。元组提供了类似占位符的功能:std::ignore。满足上面的需求,只需要在索引为奇数的位置填上std::ignore。一个例子:

std::tuple<char, int, long, std::string> fourth('A', 2, 3, "4");

// 定义变量,保存解包结果
char tuple_0 = '0';
int tuple_1 = 0;
long tuple_2 = 0;
std::string tuple_3("");

// 使用占位符
std::tie(tuple_0, std::ignore, tuple_2, std::ignore) = fourth;

// 输出解包结果
std::cout << "tuple_0 = " << tuple_0 << "\n"; //tuple_0 = A
std::cout << "tuple_1 = " << tuple_1 << "\n"; //tuple_1 = 0
std::cout << "tuple_2 = " << tuple_2 << "\n"; //tuple_2 = 3
std::cout << "tuple_3 = " << tuple_3.c_str() << "\n"; //tuple_3 =

元组连接(拼接)

使用 std::tuple_cat 执行拼接。

std::tuple<char, int, double> first('A', 1, 2.2f);

// 组合到一起, 使用auto, 自动推导
auto second = std::tuple_cat(first, std::make_tuple('B', std::string("-=+")));
// 组合到一起,可以知道每一个元素的数据类型时什么 与 auto推导效果一样
std::tuple<char, int, double, char, std::string> third = std::tuple_cat(first, std::make_tuple('B', std::string("-=+")));

// 输出合并后的元组内容
int index = 0;
std::cout << index++ << " = " << std::get<0>(second) << "\n"; //0 = A
std::cout << index++ << " = " << std::get<1>(second) << "\n"; //1 = 1
std::cout << index++ << " = " << std::get<2>(second) << "\n"; //2 = 2.2

std::cout << index++ << " = " << std::get<3>(second) << "\n"; //3 = B
std::cout << index++ << " = " << std::get<4>(second).c_str() << "\n"; //4 = -=+

std::cout << index++ << " = " << std::get<0>(second) << "\n"; //0 = A
std::cout << index++ << " = " << std::get<1>(second) << "\n"; //1 = 1
std::cout << index++ << " = " << std::get<2>(second) << "\n"; //2 = 2.2

std::cout << index++ << " = " << std::get<3>(second) << "\n"; //3 = B
std::cout << index++ << " = " << std::get<4>(second).c_str() << "\n"; //4 = -=+

遍历

这里将采用的时 递归遍历,需要注意,考虑爆栈的情况。其实,tuple也是基于模板的STL容器。 因为其可以容纳多个参数,且每个参数类型可不相同,遍历输出则涉及到参数展开的情况,这里以递归的方式实现遍历,核心代码:

#include <iostream>
#include <tuple>

template<typename Tuple, size_t N>
struct tuple_show
{
	static void show(const Tuple& t, std::ostream& os)
	{
		tuple_show<Tuple, N - 1>::show(t, os);
		os << ", " << std::get<N - 1>(t);
	}
};


// 偏特性,可以理解为递归的终止
template<typename Tuple>
struct tuple_show < Tuple, 1>
{
	static void show(const Tuple& t, std::ostream& os)
	{
		os << std::get<0>(t);
	}
};

// 自己写个函数,调用上面的递归展开,
template<typename... Args>
std::ostream& operator << (std::ostream& os, const std::tuple<Args...>& t)
{
	os << "[";
	tuple_show<decltype(t), sizeof...(Args)>::show(t, os);
	os << "]";

	return os;
}

int main()
{
	auto t1 = std::make_tuple(1, 'A', "-=+", 2);
	std::cout << t1;

	return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/554323.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 是什么?与传统的 Spring 框架有何不同?

Spring Boot是一个基于Spring框架的快速开发框架&#xff0c;它使用了约定大于配置的方式&#xff0c;可以帮助开发人员快速搭建基于Spring的Web应用程序。相较于传统的Spring框架&#xff0c;Spring Boot的优势在于自动化配置、嵌入式Web容器、依赖管理等方面。本文将详细介绍…

【活动预告】数据集成引擎BitSail遇上CDC

BitSail是字节跳动开源数据集成引擎&#xff0c;于2022年10月26日宣布开源&#xff0c;可支持多种异构数据源间的数据同步&#xff0c;并提供离线、实时、全量、增量场景下全域数据集成解决方案。BitSail支撑了字节内部众多的业务线&#xff0c;支持多种数据源之间的批式/流式/…

码上行动:零基础学会Python编程

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 欢迎来到 Crossin的编程教室 &#xff01;Crossin的新书《码上行动&#xff1a;零基础学会Python编程》终于和大家见面啦&#xff01; 本书力求做到浅显易懂&#xff0c;让完全没有编程经验的零基础“小白”也能学会Pytho…

【网络】IP地址和静态路由

目录 &#x1f341;IP地址的格式 子网掩码 &#x1f341;路由器基本原理与配置 配置IP地址通信 &#x1f341;ARP协议和ICMP协议 &#x1f9e7;广播和广播域的概念 &#x1f9e7;ARP协议 &#x1f9e7;ICMP协议 &#x1f341;静态路由和默认路由 &#x1f9e7;路由原理 &#x…

【Python】判断语句 ① ( if 语句 | if 语句语法 | 代码示例 )

文章目录 一、if 语句语法二、代码示例1、代码示例 - 触发 if 语句2、代码示例 - 不触发 if 语句 一、if 语句语法 在 Python 中 , 使用 if 语句进行判断 , 语法格式如下 : if 判断条件,布尔类型变量或表达式:条件成立,布尔类型变量或表达式为 True 执行的代码判断条件没有括号…

Ansys Speos 2023 R1新功能 | Texture可视化纹理提升视觉感知

Ansys Speos 2023 R1 新功能介绍 Ansys Speos 持续推动创新&#xff0c;为光学设计人员提供精确、高性能的仿真功能。2023 R1 新版本提供强大的功能&#xff0c;可加快结果生成速度、提高仿真精度并扩展与其他 Ansys 产品的互操作性。 更新Texture映射预览&#xff0c;为textur…

如何区别BI、大数据、信息化和数字化转型

商业智能BI可以实现业务流程和业务数据的规范化、流程化、标准化&#xff0c;打通ERP、OA、CRM等不同业务信息系统&#xff0c;整合归纳企业数据&#xff0c;利用数据可视化满足企业不同人群对数据查询、分析和探索的需求&#xff0c;从而为管理和业务提供数据依据和决策支持。…

日用行业外贸ERP软件系统,提高工作效率降低成本

日用行业是一个广泛的行业&#xff0c;包括了许多不同的产品&#xff0c;如家居用品、化妆品、个人护理用品、厨房用具等等。日用行业产品出口&#xff0c;也是我国传统外贸产业之一&#xff0c;在外贸市场来说相对有竞争力优势&#xff0c;在国际贸易中具有很大的需求和市场潜…

抓取鼠标动画

今天给大家分享一个抓取鼠标的动画&#xff0c;嗯&#xff0c;真的是抓取鼠标&#xff01; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><link href…

C++ 位图及其应用

前言 现实生活中&#xff0c;有很多场景是需要处理数据量很大的数据的&#xff0c;比如&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中。 一看到这样的题&#xff0c;我们可能想到的就是 …

悬赏问答|互助社区 X3.5正式版 1.5

模板演示站: 以下3个演示地址均为本模板设置的不同界面效果,演示站已启用了我们百变百搭-APP手机版,如需体验手机版可使用手机浏览器或微信中打开: 模板演示效果地址1:http://demo.1009.com.cn/012 模板演示效果地址2:http://demo.1009.com.cn/012a 模板演示效果地址3:h…

Handler相关问题

Handler相关问题 1、设计 Handler 的初衷&#xff1f;2、一个线程有几个 Looper&#xff1f;几个 Handler&#xff1f;3、Handler 内存泄漏原因&#xff1f; 以及最佳解决方案&#xff1f;4、为何主线程可以 new Handler&#xff1f;如果想要在子线程中 new Handler 要做些什么…

docker是怎么决定容器内容存储到哪个目录的?(存储驱动决定的)(乱七八糟的)(df -Th查看目录文件系统类型、查看文件系统类型)

文章目录 docker是怎么决定容器内容存储到哪个目录的&#xff1f;docker对我/var这个目录有没有什么要求&#xff0c;比如要求它的文件系统是指定的类型如果我Docker的默认存储驱动是overlay2&#xff0c;但是我/var目录的文件系统不是overlay2&#xff0c;这没影响吗&#xff…

人工智能MINIST手写数字识别之MINIST概念

MNIST是一个简单的视觉计算数据集,它是像下面这样手写的数字图片: MNIST 每张图片还额外有一个标签记录了图片上数字是几,例如上面几张图的标签就是:5、0、4、1。 MINIST数据 MINIST的数据分为2个部分:55000份训练数据(mnist.train)和10000份测试数据(mnist.test)。这…

Doo Prime 德璞资本:初学者必看!期货是怎么交易的四大技能

期货交易是一种金融衍生品交易&#xff0c;是指在未来某个约定的时间和价格上&#xff0c;按照合约规定的标的物进行买卖的交易方式。它是一种非常重要的投资方式&#xff0c;因为它可以帮助投资者在风险管理方面更好地掌握市场。 期货的交易方式非常多样化&#xff0c;尤其是…

【51单片机】:串口通信控制LED亮灭任务

学习目标&#xff1a; 使用51单片机的串口通信&#xff0c;当串口通信助手 发送字符串 on led开启 发送字符串 off led关闭 并且串口助手实时返回 发送的字符串 学习内容&#xff08;代码&#xff09;&#xff1a; 第一种方法&#xff0c;使用数组依次判断接收到的字…

凝聚青年力量,打造数字化人才队伍

当代青年人勇于探索、敢于创新、勤于变革&#xff0c;积极承担社会责任。这与ABeam倡导的「Build Beyond As One.™」的品牌理念不谋而合。ABeam的青年员工是未来社会的中坚力量&#xff0c;也正用他们的青春能量助力ABeam在中国的发展。 01 新兴青年力量 对ABeam而言&#…

走进工厂,认识静电测试仪器——使用方法和注意事项

随着科技的不断发展,静电测试仪器越来越多地被人们所使用。但是有些人对静电测试仪的使用方法和注意事项还不是很了解。 1&#xff1a;静电测试仪器的基本知识 静电测试仪器是一种用来测量电源电压、电流和电容器的材料。通常&#xff0c;静电测试仪器由一个电阻器或一组绝缘…

R语言丨Pheatmap绘制基因表达量热图

Pheatmap绘制基因表达量热图 论文中展示基因表达量变化通常使用热图&#xff0c;今天分享一个快速绘制不同基因在各处理下表达量变化的方法&#xff0c;使用R语言中pheatmap包&#xff0c;它可以用于可视化数据集中的数值&#xff0c;以便更好地理解数据之间的关系和模式。 …

STM32单片机WIFI教室灯光控制系统人数自动灯光温度时间

实践制作DIY- GC0135-WIFI教室灯光控制系统 一、功能说明&#xff1a; 基于STM32单片机设计-WIFI教室灯光控制系统 二、功能介绍&#xff1a; 电路&#xff1a;STM32F103C最小系统板DS18B20温度传感器LCD1602显示器ESP8266WIFI模块4个红外槽型光电传感器3个LED灯多个按键蜂鸣…