当前位置: 首页 > news >正文

C++之std::tuple(一) : 使用

相关系列文章

C++之std::tuple(一) : 使用

C++三剑客之std::variant(一) : 使用

C++三剑客之std::variant(二):深入剖析

目录

1.简介

2.创建元组

2.1.直接初始化方式

2.2.使用花括号初始化列表方式(C++11及以上版本)

2.3.make_tuple方式

2.4.使用std::tie()函数方式

3.元素访问

3.1.std::get()方式

3.2.使用结构化绑定(C++17及以上)

3.3.遍历元素

4.获取std::tuple的size

5.获取元组中的元素类型

6.std::forward_as_tuple

7.std::tuple_cat

8.总结


1.简介

        C++11之后引入了std::tuple,俗称元组,元组(tuple)是一种用于组合多个不同类型的值的数据结构。元组可以将不同类型的数据打包在一起,类似于一个容器,可以按照索引顺序访问其中的元素。元组的大小在编译时确定,不支持动态添加或移除元素。std::tuple的定义如下:

template<class... Types>
class tuple;

        std::tuple类似互C语言的结构体,不需要创建结构体而又有结构体的特征,在某些情况下可以取代结构体而使得程序更加简洁,直观。std::tuple理论上可以定义无数多个不同类型的成员变量。特别是你需要在函数之间返回多个值时,或者需要一次性处理多个相关值时,使用元组可以简化代码并提高可读性。

2.创建元组

2.1.直接初始化方式

//显示初始化
std::tuple<bool, int, double, std::string>  a(true, 1, 3.0, "1112222");

2.2.使用花括号初始化列表方式(C++11及以上版本)

//显示初始化
std::tuple<bool, int, double, std::string>  a{true, 1, 3.0, "1112222"};

2.3.make_tuple方式

//显示初始化
std::tuple<bool, int, double, std::string> a = make_tuple(true, 1, 3.0, "1112222");//隐式初始化
auto b = make_tuple(true, 1, 3.0, "1112222");

2.4.使用std::tie()函数方式

 std::tie定义为:

template<class... Types>
constexpr tuple<Types&...> tie (Types&... args) noexcept;
std::tie生成一个tuple,此tuple包含的分量全部为实参的引用,与make_tuple完全相反。主要用于从tuple中提取数据。例如:
bool myBool;
int myInt;
double myDouble;
std::string myString;std::tie(myBool, myInt, myDouble, myString) = std::make_tuple(true, 1, 3.0, "1112222");

如果是要忽略某个特定的元素,还可以使用std::ignore来占位,例如:

bool myBool;
std::string myString;std::tie(myBool, std::ignore, std::ignore, myString) = std::make_tuple(true, 1, 3.0, "1112222");

3.元素访问

3.1.std::get<index>()方式

使用std::get来访问std::tuple特定的元素,如:

std::tuple<bool, int, std::string> a(true, 0, "sfsfs");
bool b = std::get<0>(a);
int  c = std::get<1>(a);
std::string d = std::get<2>(a);std::get<0>(a) = false;
std::get<2>(a) = "s344242";

3.2.使用结构化绑定(C++17及以上)

在C++17及以上版本中,还可以使用结构化绑定 (structured bindings) 的方式来创建和访问元组,可以更方便地访问和操作元组中的元素。结构化绑定允许直接从元组中提取元素并赋值给相应的变量。例如:

std::tuple<bool, int, std::string> myTuple(true, false, "Hello");
auto [a, b, c] = myTuple;

这将自动创建变量a、b和c,并将元组中相应位置的值赋给它们。

注意:

元组是不可变的(immutable)一旦创建就不能更改其元素的值。但是,可以通过解构赋值或使用std::get<index>(tuple)来获取元组中的值,并将新的值赋给它们,从而修改元组中的值。

std::tuple不支持迭代器,获取元素的值时只能通过元素索引或tie解包。给定的索引必须是在编译期间就已经确定的,不能在运行期间动态传递,否则会产生编译错误

3.3.遍历元素

        由于 tuple 自身的原因,无法直接遍历,而 get<index> 中 index 必须为运行前设置好的常数
所以 tuple 的遍历需要我们手写,代码如下:

template<class Tuple, std::size_t N>
struct VisitTuple {static void Visit(const Tuple& value) {VisitTuple<Tuple, N - 1>::Visit(value);std::cout << ' ' << std::get<N - 1>(value);return void();}
};template<class Tuple>
struct VisitTuple<Tuple, 1> {static void Visit(const Tuple& value) {std::cout << std::get<0>(value);return void();}
};template<class... Args>
void TupleVisit(const std::tuple<Args...>& value) {VisitTuple<decltype(value), sizeof ...(Args)>::Visit(value);
}

4.获取std::tuple的size

std::tuple_size的定义如下:

template< class... Types >
struct tuple_size< std::tuple<Types...> >: std::integral_constant<std::size_t, sizeof...(Types)> { };

提供对 tuple 中元素数量的访问,作为编译时常量表达式,计算std::tuple的大小。例如:

#include <iostream>
#include <tuple>template <class T>
void test(T value)
{int a[std::tuple_size_v<T>]; // 能用于编译时std::cout << std::tuple_size<T>{} << ' ' // 或运行时<< sizeof a << ' ' << sizeof value << '\n';
}int main()
{test(std::make_tuple(1, 2, 3.14));
}

可能的输出:3 12 16

5.获取元组中的元素类型

std::tuple_element定义如下:

template< std::size_t I, class... Types >
class tuple_element< I, tuple<Types...> >;

可以使用std::tuple_element<index, tuple>::type来获取元组中特定索引位置的元素类型。

#include <iostream>
#include <tuple>template <class... Args>
struct type_list
{template <std::size_t N>using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};int main()
{std::cout << std::boolalpha;type_list<int, char, bool>::type<2> x = true;std::cout << x << '\n';
}

输出:true

6.std::forward_as_tuple

定义如下:

template< class... Types >
tuple<Types&&...> forward_as_tuple( Types&&... args ) noexcept;
template< class... Types >
constexpr tuple<Types&&...> forward_as_tuple( Types&&... args ) noexcept;

用于接受右值引用数据生成 tuple, 与 std::make_tuple 不同的是它的右值是引用的,当修改其值的时候,原来赋值所用的右值也将修改,实质上就是赋予了它地址。同std::tie一样,也是生成一个全是引用的tuple,不过std::tie只接受左值,而std::forward_as_tuple左值、右值都接受。主要是用于不损失类型属性的转发数据。

注意此处 tuple 内的类型应为引用,否则相当于 std::make_tuple。例如:

signed main(int argc, char *argv[]) {int a = 123, c = 456;float b = 33.f, d = .155;std::tuple<int&, float&, int&, float&> tu = std::forward_as_tuple(a,b,c,d);std::get<0> (tu) = 2;std::get<1> (tu) = 4.5f;std::get<2> (tu) = 234;std::get<3> (tu) = 22.f;std::cout << a << std::endl; // 2std::cout << b << std::endl; // 4.5std::cout << c << std::endl; // 234std::cout << d << std::endl; // 22return 0;
}

注意:若参数是临时量,则 forward_as_tuple 不延续其生存期;必须在完整表达式结尾前使用它们。

7.std::tuple_cat

        此函数接受多个tuple作为参数,然后返回一个tuple。返回的这个tuple将tuple_cat的参数中的tuple的所有元素按所属的tuple在参数中的顺序以及其在tuple中的顺序排列成一个新的tuple。新tuple中元素的类型与参数中的tuple中的元素的类型完全一致。例如:

#include <iostream>
#include <string>
#include <tuple>// 打印任何大小 tuple 的辅助函数
template<class Tuple, std::size_t N>
struct TuplePrinter
{static void print(const Tuple& t){TuplePrinter<Tuple, N - 1>::print(t);std::cout << ", " << std::get<N-1>(t);}
};template<class Tuple>
struct TuplePrinter<Tuple, 1>
{static void print(const Tuple& t) {std::cout << std::get<0>(t);}
};template<class... Args>
void print(const std::tuple<Args...>& t) 
{std::cout << "(";TuplePrinter<decltype(t), sizeof...(Args)>::print(t);std::cout << ")\n";
}
// 辅助函数结束int main()
{std::tuple<int, std::string, float> t1(10, "Test", 3.14);int n = 7;auto t2 = std::tuple_cat(t1, std::make_tuple("Foo", "bar"), t1, std::tie(n));n = 10;print(t2);
}

输出:(10, Test, 3.14, Foo, bar, 10, Test, 3.14, 10)

8.总结

std::tuple 是一种重要的数据结构,可以用于在函数参数之间传递数据,也可以作为函数的返回值。在实际项目中,我们可以灵活地使用 std::tuple,以简化代码,提高程序的性能。

后面我们将继续通过分析std::tuple源码的方式来更深层次讲解它的实现原理,值得期待哦。。。

参考:std::tuple - cppreference.com

相关文章:

C++之std::tuple(一) : 使用

相关系列文章 C之std::tuple(一) : 使用 C三剑客之std::variant(一) : 使用 C三剑客之std::variant(二)&#xff1a;深入剖析 目录 1.简介 2.创建元组 2.1.直接初始化方式 2.2.使用花括号初始化列表方式&#xff08;C11及以上版本&#xff09; 2.3.make_tuple方式 2.4.使…...

蓝桥杯嵌入式第六届真题(完成)STM32G431

蓝桥杯嵌入式第六届真题&#xff08;完成&#xff09;STM32G431 题目部分 相关文件 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program b…...

【日志记录】——主MCU 通过私有协议更新从MCU程序固件

一&#xff1a;需求分析 在一些系统较为复杂的嵌入式设备中&#xff0c;往往不止一片MCU或者处理模块&#xff0c;通常为一片主MCU负责应用逻辑处理和对外网络通信&#xff0c;其他从MCU负责实时采集处理高频数据&#xff0c;在设备运营过程中&#xff0c;往往伴随新需求或者bu…...

【0253】深入分析Query Execution(一)

下一篇:【0254】深入分析Query Execution(二) 1. 查询执行阶段(Query Execution Stages) 1.1 简单查询协议(Simple Query Protocol) 客户端-服务器协议的一个简单版本支持SQL查询执行:它将查询的文本发送到服务器,并在响应中获得完整的执行结果,而不管它包含多少行…...

编译opencv4.6问题汇总,第三方软件包见我发的资源

win10系统 python3.8.2&#xff0c;cmake-3.15.5-win64-x64&#xff0c;opencv4.6 编译方式见&#xff1a;OpenCV的编译 - 知乎 本文主要总结问题。赠人玫瑰手留余香。 问题1 Problem with installing OpenCV using Visual Studio and CMake (error code: MSB3073) 解决方法…...

Matplotlib炫酷气泡图:代码实战与参数解析【第55篇—python:Matplotlib炫酷气泡图】

文章目录 Matplotlib炫酷气泡图&#xff1a;代码实战与参数解析1. 基础气泡图2. 网格气泡图3. 自定义颜色气泡图4. 钟型气泡图5. 交互式气泡图6. 打卡气泡图7. 动态气泡图总结 Matplotlib炫酷气泡图&#xff1a;代码实战与参数解析 气泡图是一种展示数据分布、关联和趋势的强大…...

Android学习之路(29) Gradle初探

前言: 大家回想一下自己第一次接触Gradle是什么时候&#xff1f; 相信大家也都是和我一样&#xff0c;在我们打开第一个AS项目的时候&#xff0c; 发现有很多带gradle字样的文件&#xff1a;setting.gradle, build.gradle,gradle.warpper,以及在gradle文件中各种配置&#xff…...

python-自动化篇-运维-语音识别

文章目录 理论文本转换为语音使用 pyttsx使用 SAPI使用 SpeechLib 语音转换为文本 代码和效果01使用pyttsx实现文本_语音02使用SAPI实现文本_语音03使用SpeechLib实现文本_语音04使用PocketSphinx实现语音转换文本 理论 语音识别技术&#xff0c;也被称为自动语音识别&#xf…...

ElasticSearch-ElasticSearch实战-仿京东商城搜索(高亮)

注&#xff1a;此为笔者学习狂神说ElasticSearch的实战笔记&#xff0c;其中包含个人的笔记和理解&#xff0c;仅做学习笔记之用&#xff0c;更多详细资讯请出门左拐B站&#xff1a;狂神说!!! 七、ElasticSearch实战 仿京东商城搜索&#xff08;高亮&#xff09; 1、工程创建…...

解释 Python 中的描述符(Descriptor)是什么?如何在 Python 中实现一个简单的 ORM(对象关系映射)?

解释 Python 中的描述符&#xff08;Descriptor&#xff09;是什么&#xff1f;举例说明其用法。 在 Python 中&#xff0c;描述符&#xff08;Descriptor&#xff09;是一种对象属性的扩展机制&#xff0c;它允许你在访问或修改属性时执行自定义的操作。描述符是实现了特定协…...

IP数据云识别真实IP与虚假流量案例

随着互联网的普及&#xff0c;企业在数字领域面临着越来越复杂的网络威胁。为了保护网站免受虚假流量和恶意攻击的影响&#xff0c;许多企业正在采用IP数据云。本文将结合一个真实案例&#xff0c;深入探讨IP数据云如何成功准确地识别真实用户IP和虚假流量IP&#xff0c;提高网…...

signalR+websocket:实现消息实时通讯——技能提升

signalR 解决步骤1&#xff1a;npm install microsoft/signalr6.0.6 安装指定版本的microsoft/signalr&#xff0c;我这边安装的版本是6.0.6 解决步骤2&#xff1a;引入import * as signalR from microsoft/signalr; import * as signalR from microsoft/signalr; 下面第三…...

机器学习入门-----sklearn

机器学习基础了解 概念 机器学习是人工智能的一个实现途径 深度学习是机器学习的一个方法发展而来 定义:从数据中自动分析获得模型,并利用模型对特征数据【数据集:特征值+目标值构成】进行预测 算法 数据集的目标值是类别的话叫做分类问题;目标值是连续的数值的话叫做回…...

双非本科准备秋招(15.3)—— 力扣二叉树

今天学了二叉树结点表示法&#xff0c;建树代码如下。 public class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val val;this.left …...

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理 2024/2/3 21:23 缘起&#xff1a;最近学习stable-diffusion-webui.git&#xff0c;在Ubuntu20.04.6下配置SD成功。 不搞精简版本&#xff1a;Miniconda了。直接上Anacoda&#xff01; …...

京东微前端框架MicroApp简介

一、MicroApp 1.1 MicroApp简介 MicroApp是由京东前端团队推出的一款微前端框架,它从组件化的思维,基于类WebComponent进行微前端的渲染,旨在降低上手难度、提升工作效率。MicroApp无关技术栈,也不和业务绑定,可以用于任何前端框架。 官网链接:https://micro-zoe.gith…...

SpringBoot 使用定时任务(SpringTask)

Spring3.0以后自带的task&#xff0c;可以将它看成一个轻量级的Quartz&#xff0c;而且使用起来比Quartz简单许多。 使用步骤&#xff1a; 1.导入坐标 在spring-boot-starter-web坐标中&#xff0c;就包含了SpringTask&#xff0c;所以一般的Web项目都包含了。 <depende…...

国标GB/T 28181详解:设备视音频文件检索消息流程

目 录 一、设备视音频文件检索 二、设备视音频文件检索的基本要求 三、命令流程 1、流程图 2、流程描述 四、协议接口 五、产品说明 六、设备视音频文件检索的作用 七、参考 在国标GBT28181中&#xff0c;定义了设备视音频文件检索消息的流程&#xff0c;主…...

openssl自签名CA根证书、服务端和客户端证书生成并模拟单向/双向证书验证

1. 生成根证书 1.1 生成CA证书私钥 openssl genrsa -aes256 -out ca.key 2048 1.2 取消密钥的密码保护 openssl rsa -in ca.key -out ca.key 1.3 生成根证书签发申请文件(csr文件) openssl req -new -sha256 -key ca.key -out ca.csr -subj "/CCN/STFJ/LXM/ONONE/OU…...

NIO Selector简介

1.Selector和Channel关系 Selector一般称为选择器&#xff0c;也叫多路复用器&#xff0c;NIO的核心组件&#xff0c;用于检查一个或多个Channel的状态是否处于可读、可写的状态。 2.可选择通道 &#xff08;1&#xff09;不是所有的channel都能被selector复用&#xff0c;…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...