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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MIT 6.S081】2020, 实验记录(5),Lab: lazy allocation

目录 Task 1: Eliminate allocation from sbrk()Task 2: Lazy allocationTask 3: Lazytests and Usertests 在学习了 page fault 这一节课后&#xff0c;了解了操作系统是如何结合 page table 和 trap 利用 page fault 来实现一系列的神奇的功能。这个 lab 就是在 XV6 中实现 l…

[SWPUCTF 2021 新生赛]easyupload2.0

一开始我通过cobaltstrike写一个文件上传的木马它不允许上传php文件 我这边写了一句话木马通过burp拦截修改后缀为phtml然后通过蚁剑找flag

【数据结构】链表OJ面试题2(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 休息一天&#xff0c;今天继续刷题&#xff01; 2.OJ题目训练 1. 编写代码&#xff0c;以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在大于或等于x的结点之前 。链表分割_牛客题霸_牛客网 思路 既然涉及…

Acwing第 141 场周赛

A题 签到模拟即可 B题 单独考虑每一个a[i]&#xff0c;如果i要是答案需要指针移动多少次&#xff0c;然后算完&#xff0c;排个序&#xff0c;指针移动最少的就是答案。 #include <bits/stdc.h> #define int long long #define rep(i,a,b) for(int i (a); i < (…

【QT+QGIS跨平台编译】之二十二:【FontConfig+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、FontConfig介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、FontConfig介绍 FontConfig 是一个用于配置和定制字体的库&#xff0c;广泛应用于基于X Window系统的操作系统中&#xff0c;尤其是在Linux和Unix-like系统中。它为应用程序提供了一种统一的…

车载测试Vector工具——基于DoIP的ECU/车辆的连接故障排除

车载测试Vector工具——基于DoIP的ECU/车辆的连接故障排除 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和…

【周总结】Programmer‘s weekend routine---First week of February

总结 工作&#xff1a; 参加项目重构方案讨论会议、个人任务计划分期以及工期安排、项目初步重构开发 日常&#xff1a;参加年会&#xff08;阳光普照奖都莫得&#xff09; 2024.2.3 阴 不冷 连着一周的雨&#xff0c;我那袜子挂两三天了还能挤出水。。离谱、莆…

MySQL全表扫描:性能杀手的隐患与优化策略

MySQL全表扫描&#xff1a;性能杀手的隐患与优化策略 MySQL数据库作为常用的关系型数据库管理系统之一&#xff0c;全表扫描问题一直困扰着开发者。本文将深入剖析MySQL全表扫描的原理、其对性能的严重影响&#xff0c;同时提供一系列优化策略&#xff0c;助您高效应对MySQL性能…

2.3作业

一&#xff0e;选择题 1、适宜采用inline定义函数情况是&#xff08;C&#xff09; A. 函数体含有循环语句 B. 函数体含有递归语句 C. 函数代码少、频繁调用 D. 函数代码多、不常调用 2、假定一个函数为A(int i4, int j0) {;}, 则执行“A (1);”语句后&#xff0c;i和j的值分别…

TQ15EG开发板教程:开发板资源介绍

时钟资源 采用时钟芯片CDCM6208提供系统时钟 PL端时钟 PS 收发器时钟 PL收发器时钟 电源 BANK500 BANK501 BANK502 BANK503(专用) 1.8V 1.8V 1.8V 1.8V PS端外设 QSPI 采用2片MT25QU256 拼接成8bit的QSPI存储系统。采用1.8V供电 SD卡 SATA接口 PS端以太网接口 D…

字符数组的学习

前言&#xff1a; 在前面我们介绍过字符型数据是以字符的ASCII码储存在存储单元中&#xff0c;一般占一个字节&#xff0c;由于 ASCII码也属于整数类型&#xff0c;因此在C99标准中把字符类型归纳为整数类型中的一种&#xff0c;由于字符数据 的应用比较广泛&#xff0c;尤其…

演讲回顾:如何为大规模研发团队加速CI构建,实现高效流水线

近日&#xff0c;龙智联合Atlassian举办的DevSecOps研讨会年终专场”趋势展望与实战探讨&#xff1a;如何打好DevOps基础、赋能创新”在上海圆满落幕。龙智Atlassian技术与顾问咨询团队&#xff0c;以及清晖、JamaSoftware、CloudBees等生态伙伴的嘉宾发表了主题演讲&#xff0…