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

tuple 简易实现(C++ 模板元编程)

std::tuple

在标准库里面,tuple主要有下面四个类模板 or 函数模板

  • tuple
  • tuple_size
  • tuple_element
  • get

在后续有实现:tuple_size_v = tuple_size::valuetuple_element_t = tuple_element::type

事例Example:

auto tup = std::tuple<int, float, double, std::string>(0, 1.0, 2.0, "aaa");
std::cout << std::get<0>(tup) << " " << std::get<1>(tup)<< " " << std::get<2>(tup) << " " << std::get<3>(tup) << "\n";std::cout << std::tuple_size<decltype(tup)>::value << "\n";
std::cout << std::tuple_size_v<decltype(tup)> << "\n";std::tuple_element<3, decltype(tup)>::type a = "aaa";
std::cout << a << "\n";
std::tuple_element_t<3, decltype(tup)> b = "aaa";
std::cout << b << "\n";

sample:tuple

tuple

仿造stl:tuple的实现,采用模板递归继承的方式:

template<typename ...Ts> struct tuple;template<typename T> struct tuple<T> {using type = tuple;using value_type = T;T value_;
};template<typename T, typename ...Ts> struct tuple<T, Ts...> {using type = tuple;using value_type = T;using super_type = tuple<Ts...>;T value_;super_type rest_;
};

添加构造函数

template<typename Tv>
requires std::is_same_v<std::decay_t<Tv>, T>
tuple(Tv&& value) : value_(std::forward<Tv>(value)) {}
template<typename Tv, typename ...Tvs>
requires std::is_same_v<std::decay_t<Tv>, T>
tuple(Tv&& value, Tvs&& ...rest): value_(std::forward<Tv>(value)),rest_(super_type(std::forward<Tvs>(rest)...)) {}

test:

const std::string str1 = "lifehappy";
tuple<int, float, double, std::string> a1(114514, 114.514f, 114.514, std::move(str1));
std::cout << a1.value_ << " " << a1.rest_.value_ << " " << a1.rest_.rest_.value_ << " " << a1.rest_.rest_.rest_.value_ << "\n";
std::cout << str1 << " str1\n";std::string str2 = "lifehappy";
tuple<int, float, double, std::string> a2(114514, 114.514f, 114.514, std::move(str2));
std::cout << a2.value_ << " " << a2.rest_.value_ << " " << a2.rest_.rest_.value_ << " " << a2.rest_.rest_.rest_.value_ << "\n";
std::cout << str2 << " str2\n";

114514 114.514 114.514 lifehappy
lifehappy str1
114514 114.514 114.514 lifehappy
str2

为了让大家方便访问tuple里的内容,并没有采用继承的方式实现,但是,在后续的类模板中,均套用一下tuple类模板:

template<typename ...Ts> struct tuple;template<typename T> struct tuple<T> {using type = tuple;using value_type = T;T value_;template<typename Tv>requires std::is_same_v<std::decay_t<Tv>, T>tuple(Tv&& value) : value_(std::forward<Tv>(value)) {}tuple() {}~ tuple() {}
};template<typename T, typename ...Ts> struct tuple<T, Ts...> : tuple<Ts...> {using type = tuple;using value_type = T;using super_type = tuple<Ts...>;T value_;template<typename Tv, typename ...Tvs>requires std::is_same_v<std::decay_t<Tv>, T>tuple(Tv&& value, Tvs&& ...rest): value_(std::forward<Tv>(value)),super_type(std::forward<Tvs>(rest)...) {}tuple() {}~ tuple() {}
};

tuple_size

template<typename T> struct tuple_size {};template<typename ...Ts>
struct tuple_size<tuple<Ts...>> : std::integral_constant<int, sizeof...(Ts)> {};template<typename T>
constexpr static int tuple_size_v = tuple_size<T>::value;

tuple_element

template<int N, typename T> struct tuple_element {};template<int N, typename ...Ts>
struct tuple_element<N, tuple<Ts...>> : tuple_element<N - 1, typename tuple<Ts...>::super_type> {};template<typename ...Ts>
struct tuple_element<0, tuple<Ts...>> { using type = tuple<Ts...>::value_type; };template<int N, typename T>
using tuple_element_t = tuple_element<N, T>::type;

get

由于继承,所以可以通过static_cast<T>(tuple)T必须是满足条件的某个基类,那么先要实现一个获得第几代父亲类型的类模板:

template<int N, typename T> struct tuple_type_impl {};template<int N, typename ...Ts>
struct tuple_type_impl<N, tuple<Ts...>>: tuple_type_impl<N - 1, typename tuple<Ts...>::super_type> {};template<typename ...Ts>
struct tuple_type_impl<0, tuple<Ts...>> {using type = tuple<Ts...>::type;
};template<int N, typename T>
using tuple_type = tuple_type_impl<N, T>::type;

接着就可以通过static_cast得到其对应的类型value了:

template<int N, typename ...Ts>
auto&& get(tuple<Ts...> &tup) {using type = tuple_type<N, tuple<Ts...>>;return static_cast<type&>(tup).value_;
}

完整代码

#include <iostream>
#include <type_traits>template<typename ...Ts> struct tuple;template<typename T> struct tuple<T> {using type = tuple;using value_type = T;T value_;template<typename Tv>requires std::is_same_v<std::decay_t<Tv>, T>tuple(Tv&& value) : value_(std::forward<Tv>(value)) {}tuple() {}~ tuple() {}
};template<typename T, typename ...Ts> struct tuple<T, Ts...> : tuple<Ts...> {using type = tuple;using value_type = T;using super_type = tuple<Ts...>;T value_;template<typename Tv, typename ...Tvs>requires std::is_same_v<std::decay_t<Tv>, T>tuple(Tv&& value, Tvs&& ...rest): value_(std::forward<Tv>(value)),super_type(std::forward<Tvs>(rest)...) {}tuple() {}~ tuple() {}
};template<typename T> struct tuple_size {};template<typename ...Ts>
struct tuple_size<tuple<Ts...>> : std::integral_constant<int, sizeof...(Ts)> {};template<typename T>
constexpr static int tuple_size_v = tuple_size<T>::value;template<int N, typename T> struct tuple_element {};template<int N, typename ...Ts>
struct tuple_element<N, tuple<Ts...>> : tuple_element<N - 1, typename tuple<Ts...>::super_type> {};template<typename ...Ts>
struct tuple_element<0, tuple<Ts...>> { using type = tuple<Ts...>::value_type; };template<int N, typename T>
using tuple_element_t = tuple_element<N, T>::type;template<int N, typename T> struct tuple_type_impl {};template<int N, typename ...Ts>
struct tuple_type_impl<N, tuple<Ts...>>: tuple_type_impl<N - 1, typename tuple<Ts...>::super_type> {};template<typename ...Ts>
struct tuple_type_impl<0, tuple<Ts...>> {using type = tuple<Ts...>::type;
};template<int N, typename T>
using tuple_type = tuple_type_impl<N, T>::type;template<int N, typename ...Ts>
auto&& get(tuple<Ts...> &tup) {using type = tuple_type<N, tuple<Ts...>>;return static_cast<type&>(tup).value_;
}int main() {const std::string str1 = "lifehappy";tuple<int, float, double, std::string> a1(114514, 114.514f, 114.514, std::move(str1));// std::cout << a1.value_ << " " << a1.rest_.value_ << " " << a1.rest_.rest_.value_ << " " << a1.rest_.rest_.rest_.value_ << "\n";// std::cout << str1 << " str1\n";std::string str2 = "lifehappy";tuple<int, float, double, std::string> a2(114514, 114.514f, 114.514, std::move(str2));// std::cout << a2.value_ << " " << a2.rest_.value_ << " " << a2.rest_.rest_.value_ << " " << a2.rest_.rest_.rest_.value_ << "\n";// std::cout << str2 << " str2\n";std::cout << tuple_size_v<decltype(a1)> << " " << tuple_size<decltype(a2)>::value << "\n";std::cout << std::is_same_v<tuple_element<0, decltype(a1)>::type, tuple_element_t<0, decltype(a1)>> << " "<< std::is_same_v<tuple_element<1, decltype(a1)>::type, tuple_element_t<1, decltype(a1)>> << " "<< std::is_same_v<tuple_element<2, decltype(a1)>::type, tuple_element_t<2, decltype(a1)>> << " "<< std::is_same_v<tuple_element<3, decltype(a1)>::type, tuple_element_t<3, decltype(a1)>> << "\n";std::cout << get<0>(a1) << " " << get<1>(a1) << " "<< get<2>(a1) << " " << get<3>(a1) << "\n";get<0>(a2) = 415411;std::cout << get<0>(a2) << " " << get<1>(a2) << " "<< get<2>(a2) << " " << get<3>(a2) << "\n";return 0;
}

4 4
1 1 1 1
114514 114.514 114.514 lifehappy
415411 114.514 114.514 lifehappy

相关文章:

tuple 简易实现(C++ 模板元编程)

std::tuple 在标准库里面&#xff0c;tuple主要有下面四个类模板 or 函数模板 tupletuple_sizetuple_elementget 在后续有实现&#xff1a;tuple_size_v tuple_size::value和tuple_element_t tuple_element::type。 事例Example&#xff1a; auto tup std::tuple<in…...

Http代理与socks5代理有何区别?如何选择?(二)

上篇文章我们基本分别了解了http代理与socks5代理的定义与优缺点&#xff0c;接下来我们继续来了解http代理与socks5代理之间的比较与区别。 一、两者的比较 1、功能比较 HTTP代理专门用于Web流量&#xff0c;并在处理HTTP和HTTPS协议方面非常高效。它们可以修改正在传输的数…...

java中main方法和@Test注解的区别

Java的main方法和Test注解在用途和功能上有很大的区别。 main方法是Java应用程序的入口点。当你运行一个Java程序时&#xff0c;JVM会首先查找具有public static void main(String[] args)签名的类&#xff0c;并从这个方法开始执行程序。main方法通常用于控制程序的启动、执行…...

C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】

文章目录 STL 代码示例1、迭代器2、算法3、array容器示例4、vector示例5、deque&#xff08;double ended queue&#xff0c;双端数组&#xff09;示例6、list&#xff08;链表&#xff09;容器7、set示例8、map示例9、stack 示例10、queue示例11、priority_queue &#xff08;…...

力扣:求最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 示例1: 输入: strs ["flower", "flow" , "flight"] 输出: "fl" 示例2: 输入: strs ["dog","racecar","car&…...

Redis入门04-消息通知

目录 Redis中的消息通知 命令行操作 Redis中的管道 Redis中的消息通知 Redis可以用作消息队列的中间件&#xff0c;它提供了一种轻量级、高性能的消息传递机制&#xff0c;适用于实时通信、任务队列、事件处理等各种应用。以下是有关如何使用Redis作为消息队列的一些重要信…...

关于idea使用的一些操作设置

关于idea使用的一些操作设置 1. 常用的一下设置1.1 快捷键相关1.2 配置自动生成注释&#xff08;类、方法等&#xff09;1.3 maven项目相关1.4 常见其他的一些操作设置 2. IntelliJ IDEA 取消param注释中参数报错提示3. idea同时打开多个文件&#xff0c;导航栏不隐藏、自动换行…...

CLion 2023.2.2(C ++ IDE智能代码编辑器)

CLion 2023是一款跨平台C/C集成开发环境&#xff08;IDE&#xff09;。它为Mac用户提供了高效的编程体验&#xff0c;帮助程序员们在Mac平台上进行C/C开发。 CLion 2023支持多种编译器和调试器&#xff0c;并具有强大的代码分析和导航功能。它还为用户提供了许多便捷的工具和插…...

企业级API资产如何管理

在当今数字化时代&#xff0c;API已成为企业开发和创新的重要工具&#xff0c;如何高效地管理和调度这些资产成为了企业发展的重要课题。API资产管理的出现&#xff0c;为企业解决了这一难题&#xff0c;通过合理管理和利用API资产&#xff0c;企业可以更好地推动业务发展&…...

Git https方式拉的代码IDEA推送代码报错

报错信息 fatal: could not read Username for ‘https://codehub-cn-south-1.devcloud.huaweicloud.com’: No such file or directory 18:18:39.885: [recovery_pattern] git -c credential.helper -c core.quotepathfalse -c log.showSignaturefalse push --progress --porc…...

C++ capacity()用法总结

1. 容器的容量 容器的size是指它已经保存的元素的数目&#xff1b;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。capacity()&#xff0c;size()&#xff0c;reserve()&#xff0c;resize()这几个都是不太容易区分的函数 functionmeancapacity()获得容…...

TensorFlow2.0教程1-Eager

文章目录 张量极其操作1 张量自定义层一、网络层layer的常见操作二、实现自定义网络层三、网络层组合自动求导一、Gradient tapes二、记录控制流三、高阶梯度自定义训练(基础)一、Variables二、示例:拟合线性模型1、定义模型2.定义损失函数3.获取训练数据4.定义训练循环张…...

Redis学习系统(持续更新中)

RedisExample 课程介绍 目标是提供一个高效、可靠的学习和实践Redis的环境。我们将通过搭建Redis集群、实现缓存数据的持久化存储、制定缓存数据的淘汰策略以及同步缓存数据等步骤来深入了解和学习Redis的特性和功能。通过这个项目&#xff0c;你可以掌握Redis的核心概念和技…...

el-select获取id和name

一般选中节点只会返回:value绑定的数据给v-model中&#xff0c;要想获取id和name一并传给后端&#xff0c;需要如下几步&#xff1a; 1、给选择框添加点击事件 input"selectChangeParent" 2、v-for中多添加一个参数 index <el-select v-model"inputForm.pr…...

最简单的驱动程序

简介 在 Linux 内核中,Makefile 和 Kconfig 是两个重要的文件,它们分别承担着不同的作用。 Makefile Makefile 是一个文本文件,用于定义编译和构建内核的规则。它使用 make 工具来管理和自动化构建过程。Makefile 定义了编译器、链接器、编译选项、目标文件、源文件等信息…...

MFC String类的初始化学习

之前写过CString的用法&#xff1b; VC CString 编程实例图解_bcbobo21cn, cstring-CSDN博客 下面单独看一下CString的各种初始化方式&#xff1b; void CTest2View::OnDraw(CDC* pDC) {CTest2Doc* pDoc GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for nati…...

vue项目使用vite设置proxy代理,vite.config.js配置,解决本地跨域问题

vue3vite4项目&#xff0c;配置代理实现本地开发跨域问题 非同源请求&#xff0c;也就是协议(protocol)、端口(port)、主机(host)其中一项不相同的时候&#xff0c;这时候就会产生跨域 vite的proxy代理和vue-cli的proxy大致相同&#xff0c;需要在vite.config.js文件中配置&…...

实用-----七牛云绑定自定义域名 配置 HTTPS

实用-----七牛云绑定自定义域名 配置 HTTPS&#xff08;无废话 无尿点&#xff09; 1.访问SSL证书购买页面 https://portal.qiniu.com/certificate/ssl 2.购买免费证书 3.补全信息 注意&#xff1a; 域名直接输入 无需 www座机号随意填 区号需要搜索 下面为示例 4. 直接确认…...

【TS篇三】类、函数、for-of循环、类型推断

文章目录 一、类1.1 基本示例1.2 继承1.3 实例成员访问修饰符1.3.1 public 开放的1.3.2 private 私有的1.3.3 protected 受保护的1.3.4 readonly 只读的1.3.5 在参数中使用修饰符 1.4 属性的存&#xff08;get&#xff09;取&#xff08;set&#xff09;器1.5 静态成员 二、函数…...

Chatgpt批量改写文章网页版可多开软件-自动登录换号生成word或者TXT

Chatgpt批量改写文章网页版可多开软件介绍&#xff1a; 1、改写后生成docx格式文档和生成txt文档二选一。 2、支持原来docx文档里带图片的改写&#xff0c;改写伪原创后的docx里也带图片。 3、软件可以设置是否开启标题改写&#xff0c;可以自定义标题改写指令。 4、可以设置…...

Modelsim 使用教程(4)—— Working With Multiple Libraries

一、概述 在文中&#xff0c;我们将练习使用多个库。在实际的项目开发过程中&#xff0c;我们可能有多个库来组织设计&#xff0c;从第三方源代码访问IP&#xff0c;或者在仿真之间共享公共部分。我们将通过创建一个包含计数器设计单元的资源库来开始本文。接下来&#xff0c;我…...

【重要】浏览器输入地址提示【您的连接不是私密连接】解决方法

在配置 kubernetes-dashboard 时&#xff0c;出现您的连接不是私密连接&#xff0c;这种情况下&#xff0c;点开高级没有进一步的操作按钮&#xff0c;这是由于我们的证书无效导致浏览器自身防护拦截&#xff0c;为了接解决这个办法我们可以使用命令 thisisunsafe 强制信任该网…...

ESP-07S烧写固件记录

一&#xff0c;固件版本。 下面是官方默认AT指令版本&#xff0c;ESP-07S 的flash大小是4MB。 AT固件汇总 | 安信可科技 (ai-thinker.com) 二&#xff0c;烧录工具。 开发工具清单 | 安信可科技 (ai-thinker.com) 三&#xff0c;下载工具及连线。 使用USB转串口工具。 四&am…...

网络编程中关于UDP套接字的一些知识点

关于UDP的介绍&#xff1a; UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种面向无连接的、不可靠的传输协议&#xff0c;它在网络编程中也起着重要的作用。 1. 低延迟&#xff1a;相比于TCP&#xff0c;UDP没有建立连接和拥塞控制的开销…...

淘宝商品评论API接口(评论内容|日期|买家昵称|追评内容|评论图片|评论视频..)

淘宝商品评论API接口是淘宝开放平台提供的一种API接口&#xff0c;可以帮助开发者获取淘宝平台上的商品评论数据。 要使用淘宝商品评论API接口&#xff0c;需要进行以下步骤&#xff1a; 注册淘宝开放平台账号&#xff0c;创建应用并获取App Key和App Secret等信息。确定需要…...

计算机网络 第五章传输层

文章目录 1 传输层的功能2 传输层两种协议&#xff1a;UDP和TCP3 端口和端口号4 UDP数据报特点和首部格式5 UDP校验6 TCP协议的特点7 TCP报文段首部格式8 TCP连接&#xff1a;三次握手建立连接9 TCP连接&#xff1a;四次挥手释放连接10 TCP可靠传输11 TCP流量控制12 TCP拥塞控制…...

cartographer,ros,路径规划近两年的工作笔记

马上转入cartographer的去ros移植了,随便记录一下研究cartographer和ros这些天来的摸鱼笔记吧虽然很多人对用ros做产品嗤之以鼻,但是我个人是不排斥的,对代码能力有限的人群来说这是产品化最快的方式! 敝帚自珍~~~继续加油~~~ 建图总结 odom 尤其是转弯的时候,存在累积误…...

react 生命周期讲解

当涉及到React组件的创建、更新和销毁过程时&#xff0c;React的生命周期方法起到了至关重要的作用。正确地理解和使用这些生命周期方法可以帮助我们在不同的阶段执行特定的操作&#xff0c;从而实现更好的组件控制和优化。 1. 挂载阶段&#xff08;Mounting&#xff09; 在组…...

什么是TCY油封?

机械由无数组件协同工作以确保平稳运行&#xff0c;其中一种不可或缺的部件是油封&#xff0c;特别是TCY油封。本文旨在阐明TCY油封的应用、其重要性以及它们如何提高机械的整体效率。 TCY油封主要用于轴密封。轴是一种旋转机器元件&#xff0c;横截面通常为圆形&#xff0c;用…...

【Vue.js】使用Element入门搭建登入注册界面axios中GET请求与POST请求跨域问题

一&#xff0c;ElementUI是什么&#xff1f; Element UI 是一个基于 Vue.js 的桌面端组件库&#xff0c;它提供了一套丰富的 UI 组件&#xff0c;用于构建用户界面。Element UI 的目标是提供简洁、易用、美观的组件&#xff0c;同时保持灵活性和可定制性 二&#xff0c;Element…...