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

c++ 中的可变参数模板与折叠表达式

c++ 11 引入了可变参数模板,c++ 17 引入了折叠表达式,比 c 语言的可变参数更加简洁灵活。这篇博客总结了一些例子。

  • …(省略号)用于可变参数(Variadic Arguments),它可以放在模板参数函数参数的后面,表示该参数是参数包(Parameter Pack),可以接收多个值。

1. 可变参数模板

递归调用是处理可变参数模板的经典方式,即通过递归地拆解参数包。

#include <iostream>

// 基本函数(终止递归)
void print() {
    std::cout << "结束" << std::endl;
}

// 可变参数模板
template <typename T, typename... Args> // 这个... 表示多种不同的变量类型
void print(T first, Args... rest) { // 这个... 表示多种不同的变量类型
    std::cout << first << " ";  // 先打印当前参数
    print(rest...);             // 递归调用,传入剩余参数, 这个... 表示多种不同的传入参数
}

int main() {
    print(1, 2.5, "Hello", 'A');  
    // 输出: 1 2.5 Hello A 结束
}

  • 需要有递归的终止函数,比折叠表达式麻烦点

  • 可变参数模板不仅可以用于函数,还可以用于 类模板。

#include <iostream>

// 可变参数类模板
template <typename... Args>
class MyClass {
public:
    MyClass() {
        std::cout << "MyClass with " << sizeof...(Args) << " template parameters\n";
    }
};

int main() {
    MyClass<int, double, char> obj1;  // 输出: MyClass with 3 template parameters
    MyClass<> obj2;                   // 输出: MyClass with 0 template parameters
}

  • sizeof…(Args) 为一种特殊的语法,用来 获取模板参数包中的参数个数。

2. 折叠表达式

C++17 引入了 折叠表达式(Fold Expressions),可以将参数包展开,并应用一个二元操作符来对这些参数进行“折叠”,将它们合并成一个单一的值。

折叠表达式有两种基本形式:

  • 左折叠(left fold), 操作从 最左侧 开始,依次将参数包中的元素与左侧的结果结合,语法:
(... op args)
  • 右折叠(right fold),操作从 最右侧 开始,依次将参数包中的元素与右侧的结果结合,语法:
(op args ...)

其中,op 表示运算符,可以是 +, -, *, /, &&, ||, << 等。可以看出,省略号在运算符左边就是左折叠,在运算符右边就是右折叠。

#include <iostream>

template <typename... Args> auto subtractLeft(Args... args) {
  return (... - args); // 左折叠,依次进行减法
}

template <typename... Args> auto subtractRight(Args... args) {
  return (args - ...); // 右折叠,依次进行减法
}

int main() {
  std::cout << subtractLeft(10, 3, 2, 1) << std::endl; // 输出是 4
  std::cout << subtractRight(10, 3, 2, 1) << std::endl; // 输出是 8

  return 0;
}

第一个函数左折叠表示 10-3-2-1=4,第二个函数右折叠表示 10-(3-(2-1))=8.

  • 可以直接对可变参数包进行操作,避免递归展开。
#include <iostream>

// 使用 C++17 折叠表达式
template <typename... Args>
void print(Args... args) {
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}

int main() {
    print(1, 2.5, "Hello", 'A');
    // 输出: 1 2.5 Hello A
}

对所有参数包求和:

#include <iostream>

template <typename... Args>
auto sum(Args... args) {
    return (args + ...); // 左折叠,将所有参数求和
}

int main() {
    std::cout << sum(1, 2, 3, 4) << std::endl; // 输出: 10
}

相关文章:

  • 简述下npm,cnpm,yarn和pnpm的区别,以及跟在后面的-g,--save, --save-dev代表着什么
  • 学习网络层
  • python unity通讯数据解析2
  • STAR Decomposition 一种针对极端事件的信号分解方法 论文精读加复现
  • 3.17学习总结
  • 【项目合集】智能语音小车-微信小程序控制
  • WebView2 nuget不能安装到unity项目中
  • 中间件 - 1.nats
  • Matlab GPU加速技术
  • 如何检查CMS建站系统的插件是否安全?
  • 使用 DrissionPage 实现网页内容自动化采集
  • Git Bisect 使用指南:高效定位引入 Bug 的提交
  • Qt之自定义界面组件 一
  • Jenkins 快讯
  • STM32G070CBT6读写FLASH中的数据
  • 浅谈Mysql数据库事务操作 用mybatis操作mysql事务 再在Springboot中使用Spring事务控制mysql事务回滚
  • ‌RTSPtoWeb, 一个将rtsp转换成webrtc的开源项目
  • 银河麒麟V10SP3Server中离线安装Docker引擎与docker-compose
  • 电池预测 | 第23讲 基于CNN-BiLSTM的锂电池剩余寿命预测,附带PPT视频讲解
  • GB9706.1-2020附件J绝缘路径参考
  • 桥,在黄岩与上海之间|劳动者的书信③
  • 《大风杀》上海首映,白客说拍这戏是从影以来的最大挑战
  • 解放日报:服务国家战略,加快建成科技创新高地
  • 两部门预拨4000万元支持山西、广西、陕西做好抗旱救灾工作
  • 外交部:中美双方并未就关税问题进行磋商或谈判
  • 美参议院通过新任美国驻华大使任命,外交部回应