c++之说_13|模板 折叠表达式

折叠表达式 可以通过形参包的的实际参数(不是类型)  展开式子

这是这里说的几种  实际上并还有一些写法

先介绍这几种吧

#include <cstdio>
template<typename T,T... n>
struct integer_sequence
{T val;
};
template<int idx,typename _Tulp>
int get(_Tulp& t)
{return 0;
}
template<typename Ret,typename ...T>
using b = Ret(*)(T...);
b<void,int,int,int,int> _fun;template<typename ...T>
void getc(T...)
{
}template<typename T, T... ints>
auto call(integer_sequence<T, ints...> int_seq)
{T _tuple;//return getc((get<ints>(_tuple))...);//return getc(get<ints>(_tuple)...);//return ((get<ints>(_tuple),...));//return (ints||...);//一元右折叠//return (...,ints);//一元左折叠//return ((5*10)+...+ints);//二元左折叠//return (ints+...+(5*10));//二元右折叠}
template<typename ...T>
auto call(T* ... c)//integer_sequence<T*, ints...> int_seq)
{//return (c -> h,...);//return (*_fun)(c -> h...);return (*_fun)(	[&](){return c->h;  }()...);// return (c&&...&&0);
}
template<typename T>
struct jk
{T h;
};int main()
{jk<int> b;b.h = 10;call(&b,&b,&b,&b);call(integer_sequence<int, 0,1,2,3>());
}

return (ints||...);//一元右折叠
  //return (...,ints);//一元左折叠
 // return ((5*10)+...+ints);//二元左折叠
  //return (ints+...+(5*10));//二元右折叠

调用处 call(integer_sequence<int, 0,1,2,3>());

我们先看一元右折叠

return (ints||...);//一元右折叠template<>
bool call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return static_cast<bool>(0) || (static_cast<bool>(1) || (static_cast<bool>(2) || static_cast<bool>(3)));
}
//实例化后是如此0|| 
(  1 || (  2 || 3 ) ) 

是的外围没有小括号了

一元左折叠

 return (...,ints);//一元左折叠template<>
int call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return ((0 , 1) , 2) , 3;
}
这个清楚多了

二元左折叠

return ((5*10)+...+ints);//二元左折叠template<>
int call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return ((((5 * 10) + 0) + 1) + 2) + 3;
}

二元右折叠

return (ints+...+(5*10));//二元右折叠template<>
int call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return 0 + (1 + (2 + (3 + (5 * 10))));
}

好了简单的折叠式子给了

现在我们来看看有点不一样的

----------------------------------------------------

return getc( ( get<ints>(_tuple) )... );

比如这里  我们能看出想法

要根据 形参包实际的参数 ints 去调用并 铺开成为 

函数 getc 的参数

ints = {0,1};return getc( (get<0>(_tuple)) , ( get<1>(_tuple)) );

实际上展开呢?

call(integer_sequence<int, 0,1,2,3>());//调用处template<>
void call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return getc((get<0>(_tuple)), (get<1>(_tuple)), (get<2>(_tuple)), (get<3>(_tuple)));
}

这个和我们之前看到的规则有些不同  什么一元二元 没用到哇

你说括号好多?不和我们平时调用的一样

return getc(get<ints>(_tuple)...);template<>
void call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return getc(get<0>(_tuple), get<1>(_tuple), get<2>(_tuple), get<3>(_tuple));
}

如此更改  括号没了

这个可以说就是 把  ... 左边的 成一个整体  get<ints>(_tuple)

有前提  必须得是在  类似于函数参数中

 return (get<ints>(_tuple)...);
这样写很遗憾是错误的
我们只能使用
一元二元的规则return (get<ints>(_tuple),...);template<>
int call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return get<0>(_tuple) , (get<1>(_tuple) , (get<2>(_tuple) , get<3>(_tuple)));
}如果这样
return ((get<ints>(_tuple),...));template<>
int call<int, 0, 1, 2, 3>(integer_sequence<int, 0, 1, 2, 3> int_seq)
{int _tuple;return (get<0>(_tuple) , (get<1>(_tuple) , (get<2>(_tuple) , get<3>(_tuple))));
}外部就会多个括号

-------------------------------------------------------------------------------------------------------------

jk<int> b;b.h = 10;call(&b,&b,&b,&b);
//调用处template<typename ...T>
auto call(T* ... c)//integer_sequence<T*, ints...> int_seq)
{return (c -> h,...);//return (*_fun)(c -> h...);// return (*_fun)(	[&](){return c->h;  }()...);// return (c&&...&&0);
}

我们还可以访问类的成员

template<>
int call<jk<int>, jk<int>, jk<int>, jk<int> >(jk<int> * __c0, jk<int> * __c1, jk<int> * __c2, jk<int> * __c3)
{return __c0->h , (__c1->h , (__c2->h , __c3->h));
}

使用函数指针

template<typename Ret,typename ...T>
using b = Ret(*)(T...);b<void,int,int,int,int> _fun;return (*_fun)(c -> h...);
template<>
void call<jk<int>, jk<int>, jk<int>, jk<int> >(jk<int> * __c0, jk<int> * __c1, jk<int> * __c2, jk<int> * __c3)
{return (*_fun)(__c0->h, __c1->h, __c2->h, __c3->h);
}

lambda函数

 return (*_fun)(	[&](){return c->h;  }()...);
template<>
void call<jk<int>, jk<int>, jk<int>, jk<int> >(jk<int> * __c0, jk<int> * __c1, jk<int> * __c2, jk<int> * __c3)
{class __lambda_41_21{public: inline /*constexpr */ int operator()() const{return __c0->h;}private: jk<int> & * __c0;public:__lambda_41_21(jk<int> & * ___c0): __c0{___c0}{}} __lambda_41_21{__c0};class __lambda_41_21{public: inline /*constexpr */ int operator()() const{return __c1->h;}private: jk<int> & * __c1;public:__lambda_41_21(jk<int> & * ___c1): __c1{___c1}{}} __lambda_41_21{__c1};class __lambda_41_21{public: inline /*constexpr */ int operator()() const{return __c2->h;}private: jk<int> & * __c2;public:__lambda_41_21(jk<int> & * ___c2): __c2{___c2}{}} __lambda_41_21{__c2};class __lambda_41_21{public: inline /*constexpr */ int operator()() const{return __c3->h;}private: jk<int> & * __c3;public:__lambda_41_21(jk<int> & * ___c3): __c3{___c3}{}} __lambda_41_21{__c3};return (*_fun)(__lambda_41_21.operator()(), __lambda_41_21.operator()(), __lambda_41_21.operator()(), __lambda_41_21.operator()());
 
大概就是这样
return (*_fun)(	[&](){return c->h;  }(),[&](){return c->h;  }(),[&](){return c->h;  }(),[&](){return c->h;  }());

从这里我们也可以看出 lambda 本质是是一个类里面

使用了 operator()

我现所知晓的折叠表达式已经说完了

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

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

相关文章

[NOI2014] 起床困难综合症

[NOI2014] 起床困难综合症 题目描述 21 21 21 世纪&#xff0c;许多人得了一种奇怪的病&#xff1a;起床困难综合症&#xff0c;其临床表现为&#xff1a;起床难&#xff0c;起床后精神不佳。作为一名青春阳光好少年&#xff0c;atm 一直坚持与起床困难综合症作斗争。通过研究…

windows上卸载完程序后,清理残余文件,无法删除的情况处理

现象&#xff1a;通常在卸载完软件后&#xff0c;要删除残余文件或者移动残余文件时候&#xff0c;会弹出来 原因&#xff1a; 因为文件被其他程序已经加载&#xff0c;处理的目标是找到使用这个文件的进程&#xff0c;然后kill掉。类似于linux上的lsof命令查找到进程号&…

C++新版本特性

目录: 前言 C11的常用新特性 auto类型推导&#xff1a; auto的限制&#xff1a; auto的应用&#xff1a; decltype类型推导&#xff1a; decltype的实际应用&#xff1a; 使用using 定义别名&#xff1a; 支持函数模板的默认模板参数 : tuple元组&#xff1a; 列表初…

Linux操作系统基础(三):虚拟机与Linux系统安装

文章目录 虚拟机与Linux系统安装 一、系统的安装方式 二、虚拟机概念 三、虚拟机的安装 四、Linux系统安装 1、解压人工智能虚拟机 2、找到解压目录中的node1.vmx 3、启动操作系统 虚拟机与Linux系统安装 一、系统的安装方式 Linux操作系统也有两种安装方式&#xf…

从零开始手写mmo游戏从框架到爆炸(十)— 集成springboot-jpa与用户表

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 集成springboot-jpa&#xff0c;不用mybatis框架一个是方便对接不同的数据源。第二个目前规划的游戏内容可能对数据库的依赖不是很大&#xff0c;jpa应该肯定能满足要求了…

阿里云服务器价格表2024最新版CPU内存带宽报价

2024年2月阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核…

2024.2.7日总结(小程序开发4)

页面导航 页面导航是页面之间的相互跳转&#xff1a; <a>链接location.href 小程序中实现页面导航的两种方式&#xff1a; 声明式导航 在页面上声明一个<navigator>导航组件通过点击<navigator>组件实现页面跳转 编程式导航 调用小程序的导航API&…

[C#] 如何使用ScottPlot.WPF在WPF桌面程序中绘制图表

什么是ScottPlot.WPF&#xff1f; ScottPlot.WPF 是一个开源的数据可视化库&#xff0c;用于在 WPF 应用程序中创建高品质的绘图和图表。它是基于 ScottPlot 库的 WPF 版本&#xff0c;提供了简单易用的 API&#xff0c;使开发人员能够通过简单的代码创建各种类型的图表&#…

极值图论基础

目录 一&#xff0c;普通子图禁图 二&#xff0c;Turan问题 三&#xff0c;Turan定理、Turan图 1&#xff0c;Turan定理 2&#xff0c;Turan图 四&#xff0c;以完全二部图为禁图的Turan问题 1&#xff0c;最大边数的上界 2&#xff0c;最大边数的下界 五&#xff0c;…

CentOS7集群配置免密登录

准备工作 提前开启三台虚拟机hadoop102、hadoop103,hadoop104,关于三台虚拟机的安装可以参考&#xff1a;https://mp.csdn.net/mp_blog/creation/editor/136010108 配置免密登录 一、分别修改三台机器的hosts,配置主机映射关系 vim /etc/hosts 文件中输入以下内容&#xf…

Web 目录爆破神器:Dirb 保姆级教程(附链接)

一、介绍 dirb 是一款用于目录爆破的开源工具&#xff0c;旨在帮助渗透测试人员和安全研究人员发现目标网站上的隐藏目录和文件。它使用字典文件中的单词来构建 URL 路径&#xff0c;然后发送 HTTP 请求来检查这些路径是否存在。 以下是 dirb 工具的一些特点和基本用法&#…

leetcode206反转链表|详细算法讲解学习

题目 https://leetcode.cn/problems/reverse-linked-list/ 这道题对于刚开始学习数据结构和算法的人来说有点难&#xff0c;是入门的重要典型题目&#xff1b;但等数据结构入门之后&#xff0c;这就会是一道非常简单的题目了。 算法一&#xff08;算法正确但超出时间限制&am…