今天写了写这方面的东西,发现文章比较少,就决定写一写。
想要知道折叠表达式是什么,我们得知道什么是可变参数,可变参数模板,在c++17之前,c++11,我们的可变参数模板都是使用递归解包,过于消耗资源且不方便,我们举几个例子吧
#include<iostream>
//设置退出条件
void show(){}
template<typename T,typename ...Args>
void show(T v, Args... args)
{
std::cout << v << ",";
show(args...);
}
void test01()
{
show(5,6.2,'*',"hello");
}
int main()
{
test01();
return 0;
}
//本质上是递归调用,函数9个步骤,传递完参数后开始输出,四轮,然后没有数据了就进入结束的重载函数,执行完后
//开始结束,销栈,销毁栈区也是四轮,相反顺序。
//c++ prime plus P670面,这种操作还有很多用法.
这是常见的c++11解包方式,我们不再赘述。
那么C++17的折叠表达式好就好在方便
#include<iostream>
template<typename... Args>
auto left_sub(Args&&... args) {
return (... - args);//左折叠
}
template<typename... Args>
auto right_sub(Args&&... args) {
return (args - ...);//右折叠
}
template<typename...Args>
auto print(Args&&...args) {
(std::cout << ... << args) << std::endl;;//打印输出的折叠表达式得使用小括号
}
int main() {
auto a = left_sub(2, 3, 4); // ((2 - ) -3 ) - 4) = -5
auto b = right_sub(2, 3, 4); // (2 - (3 - 4)) = 3
std::cout << a << "," << b << std::endl;
print(1, 2, 3, 4, 5, 6,"哈哈哈");
}
//这种可比c++11的可变参数模板要好的多
首先我们可以看出折叠表达式接收参数非常的方便,代码量很少,方便使用,但是要分清楚左结合与右结合,左结合就是从左边开始操作,反之亦然。不管是运算符操作,打印都可。
我们可以看到打印结果是没有分割的,我们举个例子如何分割。
顺便说一下有意思的变参下标
#include<iostream>
#include<string>
template<typename...Args>
auto print(Args&&...args) {
(std::cout << ... << args) << std::endl;//创建c++17的折叠表达式函数来对下面这个进行输出
}
template<typename C, typename... Idx>
void printElems2(C const& coll, Idx... idx)
{
print(coll[idx]...);
}
template<typename C, typename... Idx>
void printElems(C const& coll, Idx... idx)
{
((std::cout << coll[idx] << ","), ...);//中间用逗号隔开
}
//直接cout输出,不使用外部函数,不分割
template<typename C, typename... Idx>
void printElems3(C const& coll, Idx... idx)
{
(std::cout << ... << coll[idx]);
}
int main()
{
const int num[5]{ 1,2,3,4,5 };
printElems(num, 1, 2, 3, 4);
return 0;
}
我们提供了多种写法的输出方式。sizeof...和其他解包方式我们就不再介绍了,有兴趣可以去了解这个运算符和其他的解包,例如c语言是如何实现的可变参数,下面的是c风格的实现,且不是模板不能接收任意类型,不过毕竟cpp理想情况下兼容c,了解即可了
#include<iostream>
#include<cstdarg>
//可变参数的函数
void vair_fun(int count, ...)
{
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i)
{
int arg = va_arg(args, int);
std::cout << arg << " ";
}
va_end(args);
}