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

C++可变参数

  • 可变参数
    • C风格的可变参数
      • C风格可变参数的使用
    • C++11可变参数模板
      • 递归展开参数包
      • 参数列表展开
      • 折叠表达式
    • STL中的emplace插入接口

可变参数

C风格的可变参数

可变参数是一种语言特性,可以在函数声明中使用省略号...来表示函数接受可变数量的参数。

例如典型的printf()函数:

int printf (const char * szFormat, ...);// printf("%d + %d = %d \n", 1, 2, 1+2);

第一个参数是格式化字符串,后面的...是可变参数

//使用宏定义与可变参数
//__VA_ARGS__表示宏定义中的可变参数部分
#define LOG(format, ...) printf(format, ##__VA_ARGS__)

如果可变参数列表为空,## 会删除前面的逗号,避免语法错误


C风格可变参数的使用

在函数体内,可以使用 va_list 类型的变量和va_start, va_arg, va_end,函数来处理可变参数。

<stdarg.h> 头文件中包含

请添加图片描述请添加图片描述
请添加图片描述
请添加图片描述


paramN : 函数定义中最后一个命名参数的名称。随后调用va_arg提取的参数是后面的参数


示例:

void my_printf(const char* format,...)
{//定义一个va_list类型变量va_list argList; 	//初始化argList,获取format后面的额外参数va_start(argList, format);	//依次获取可变的参数值。需要指定参数值的数据类型while (*format != '\0') {if(*format == '%') {format++;            switch (*format) {case 'd': //整数                   cout << va_arg(argList, int) << " ";break;case 'f': //浮点数                  cout << va_arg(argList, double) << " ";break;}}format++;}//释放va_list变量va_end(argList);
}my_printf("%d, %f", 25, 3.22);

C++11可变参数模板

C++11新增特性。可变参数模板是一种用于处理具有不定数量参数的函数模板的特性。

定义:

template<class ...Args>
viod func(Args... args);

Args为参数包名,前加可变参数...进行声明。参数包中可以包含0~n个不同类型参数


通过使用参数包展开表达式,才能获取并使用参数

递归展开参数包

示例:

//当递归展开介绍,调用该终止函数
int sum() {return 0;
}// 递归情况:将第一个参数与后面的参数相加
template<typename T, typename... Args>
T sum(T first, Args... rest) {return first + sum(rest...);
}std::cout << sum(1, 2, 3, 4, 5) << std::endl; // 输出:15
std::cout << sum(10.5, 20.5, 30.5) << std::endl; // 输出:61.5

使用参数包时,需要加上展开操作符...

递归展开时,需要注意,如果没有终止函数,当参数包中的参数个数为0后,会发生死循环

上述代码的终止函数也可以写一下形式:

//当没有参数时,返回0
template<typename T>
T sum(T value) {return value;
}

参数列表展开

通过参数列表(initializer_list)获取参数包中的参数

如果参数包中的各个参数都是相同类型,这可以通过列表初始化的形式,将其转移到数组中。

template<typename... Args>
void func(Args... args) {    int dummy[] = { args...};dummy[0];//使用...
}

该操作,不支持0个参数的参数包(不能分配常量大小为0的数组)


对于不同类型的参数,可以利用参数列表结合逗号表达式,将参数包展开为逗号分隔的一系列独立的参数。

template<class T>
void doSomething(const T& t)
{...//使用
}template<typename... Args>
void myFunction(Args... args) {// 使用展开操作符将参数包展开int arr[] = { (doSomething(args), 0)...};// ...
}

通过初始化列表来初始化一个变长数组,然后再对数组arr初始化时,会执行expand函数中的逗号表达式(从左到右计算表达式并将最后一个表达式的值返回)。最终会在创建完一个int arr[sizof ...args] = {0}的数组同时,处理参数包中的参数。

当然这里的int型以及逗号表达式中的0值,都没有后续的使用意义。

myFunction(1, 2.5, "hello");//参数包展开为:
int arr[] = {(doSomething(1), 0),(doSomething(2.5), 0),(doSomething("hello"), 0)
};

如果不想在0个参数时 myFunction();,编译报错,可增加无参的重载

//可增加一个无参的函数重载,来对0个参数特殊处理
void doSomething();

折叠表达式

折叠表达式(Fold Expressions) 是 C++17 引入的一种简化可变参数模板(variadic templates)的语法特性。

有四种:

(pack op ...)			// 一元左折叠
(... op pack)			// 一元右折叠
(init op ... op pack)	// 二元左折叠
(pack op ... op init)	// 二元右折叠

使用:

template<typename... Args>
auto sum(Args... args) {return (args + ...); // 一元左折叠
}sum(1,2,3,4); // (((1 + 2) + 3) + 4)
template<typename... Args>
auto sum(Args... args) {return (... + args); // 一元右折叠
}sum(1,2,3,4); // (1 + (2 + (3 + 4)))
template<typename... Args>
auto sum_with_init(int init, Args... args) {return (init + ... + args); // 二元左折叠
}sum_with_init(0,1,2,3); // (((0 + 1) + 2) + 3)
template<typename... Args>
auto sum_with_init(int init, Args... args) {return (args + ... + init); // 二元右折叠
}sum_with_init(0,1,2,3); // (1 + (2 + (3 + 10)))

template<typename... Args>
void myFunction(Args... args) {(doSomething(args), ...); // 折叠表达式
}myFunction(1, 2.5, "hello"); 
// (doSomething(1), (doSomething(2.5), (doSomething("hello"))));
  • pack : args
  • op : ,

STL中的emplace插入接口

例如在vector容器中:
请添加图片描述

该成员函数,就是使用了可变参数模板,使用上和原来的插入接口push_back差别不大

vector<std::pair<int, string>> v;
v.push_back(make_pair( 0, "hello" ));
v.emplace_back(1, "world");

make_pair会多构建一次string对象的消耗


🦀🦀观看~~

相关文章:

C++可变参数

可变参数C风格的可变参数C风格可变参数的使用 C11可变参数模板递归展开参数包参数列表展开折叠表达式 STL中的emplace插入接口 可变参数 C风格的可变参数 可变参数是一种语言特性&#xff0c;可以在函数声明中使用省略号...来表示函数接受可变数量的参数。 例如典型的printf…...

光传输设备现状

随着运营商准备好其基础设施以应对新一代高带宽应用程序和 AI 部署&#xff0c;光传输网络 (OTN) 市场再次有望实现稳健增长。 隧道的尽头有光亮&#xff0c;OTN 市场在 2024 年最后一个季度表现强劲&#xff0c;设备供过于求的时代已经结束。 供应商表示设备订单量有所增加&…...

Python 笔记 (二)

Python Note 2 1. Python 慢的原因2. 三个元素3. 标准数据类型4. 字符串5. 比较大小: 富比较方法 rich comparison6. 数据容器 (支持*混装* )一、允许重复类 (list、tuple、str)二、不允许重复类 (set、dict)1、集合(set)2、字典(dict)3、特殊: 双端队列 deque 三、数据容器的共…...

nt!IopCompleteReques函数分析之IopUpdateOtherTransferCount和IopDequeueThreadIrp

VOID IopCompleteRequest( IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2 ) 第一部分&#xff1a; if (irp->UserEvent) { (VOID) KeSetEvent( …...

d2025329

目录 一、修复表中名字 二、患某种疾病的患者 三、最长连续子序列 四、二叉树的层序遍历 一、修复表中名字 1667. 修复表中的名字 - 力扣&#xff08;LeetCode&#xff09; concat(A,B)&#xff0c;将字符串A和B拼接left(str,len)&#xff0c;从字符串左边开始截取len个字…...

北斗导航 | 中国北斗卫星导航系统的发展历程——“三步走”战略:背景,信号频点,调制方式,短报文,等

中国北斗卫星导航系统的发展历程按照“三步走”战略逐步推进,从区域服务到全球覆盖,形成了北斗一号、北斗二号、北斗三号三代系统的迭代升级,展现了中国航天科技的自主创新与突破。以下是各阶段的核心内容与发展特点综述:一、北斗一号:中国卫星导航的奠基(1994-2003年) …...

cordova android12+升级一些配置注意事项

1.以android13为例 Cordova Android 13.0.0 cordova platform remove android cordova platform add android13.0.0Cordova Android 13.0.0 这里建议将android-studio升级到最新 build时若是需要到gradled安装失败 建议多试几次 或者直接用网页下载 找到 Android Studio 的 G…...

批量处理word里面表格的空白行

1&#xff0c;随便打开一个word文档。 2&#xff0c;按下Alt F11 VBA编辑器,在左侧的「工程资源管理器」窗口中找到Normal 项目,右键选择插入->模块。 弹出一下弹窗 3&#xff0c;输入一下代码 代码&#xff1a; Sub RemoveEmptyTableRows()Dim tbl As TableDim row As R…...

K8S学习之基础五十七:部署代码扫描工具sonarqube

部署代码扫描工具sonarqube 拉取postgres、sonarqube镜像&#xff0c;在harbor上创建postgres、sonarqube项目&#xff0c;将镜像上传至harbordocker pull postgres docker pull sonarqube docker tat postgres:latest 172.16.80.140/postgres/postgres:latest docker tat sona…...

Nginx 解决具有不安全、不正确或缺少 SameSite 属性的 Cookie方案

针对Nginx中Cookie的SameSite属性配置问题&#xff0c;以下是综合解决方案及注意事项&#xff1a; 一、基础配置方法 全局设置Cookie属性‌&#xff08;适用于Nginx直接生成Cookie&#xff09; 在nginx.conf的location块中通过add_header指令添加&#xff1a; add_header Se…...

音频知识 参数分析

通道布局 参考 通过pcm音频数据计算分贝 理解FFT和信号加窗原理及意义 dts音效大师教程...

使用 rsync 进行服务器文件同步与优化

使用 Rsync 工具在两台 Linux 服务器之间同步文件 Rsync 是一种高效的文件同步工具&#xff0c;它可以在本地或远程服务器之间同步文件和目录。Rsync 通过仅传输文件的变化部分来减少数据传输量&#xff0c;因此特别适合用于定期备份或同步大量数据。本文将详细介绍如何将 A 服…...

MySQL 的 SQL 语句执行顺序

MySQL 的 SQL 语句执行顺序并不完全按照代码的书写顺序执行&#xff0c;而是遵循一套固定的逻辑流程 1. FROM 和 JOIN 作用&#xff1a;确定查询的数据来源&#xff0c;包括表和它们的连接方式&#xff08;如 INNER JOIN, LEFT JOIN 等&#xff09;。 细节&#xff1a; 先执行…...

小型水库大坝安全及水雨情监测技术方案

一、小型水库监测系统构成 小型水库雨水情测报和大坝安全监测系统由水库监测站点、通信网络和监测平台等组成&#xff0c;系统总体架构如图所示。 水库监测站点设施包括&#xff1a;雨量计、水位计、视频监视设备、渗压计、量水堰计、变形监测仪器、数据采集仪、遥测终端、水准…...

scala简介和基础语法

Scala简介 Scala 是一门多范式&#xff08;multi-paradigm&#xff09;的编程语言&#xff0c;设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在 Java 虚拟机上&#xff0c;并兼容现有的 Java 程序。Scala 源代码被编译成 Java 字节码&#xff0c;所以它可…...

‘无法定位程序输入点kernel32.dll’详细的修复方法,一键快速修复kernel32.dll

在 Windows 系统运行过程中&#xff0c;若程序提示“无法定位程序输入点 kernel32.dll”&#xff0c;往往意味着程序调用了 kernel32.dll 中不存在或已变更的函数接口。作为系统的核心动态链接库&#xff0c;kernel32.dll 承担着内存管理、进程控制、文件操作等底层功能&#x…...

电源系统的热设计与热管理--以反激式充电器为例

前言 反激电源常用于各种电子设备中&#xff0c;比如充电器、适配器等&#xff0c;它们通过变压器进行能量转换。高温环境可能对电子元件造成影响&#xff0c;特别是像MOSFET、二极管、变压器这样的关键部件&#xff0c;导致效率变低&#xff0c;甚至可能导致功能失效。还有安…...

笔记本电脑更换主板后出现2203:System configuration is invalid,以及2201、2202系统错误的解决

笔记本电脑更换主板后启动出现2203:System configuration is invalid,以及2201、2202系统错误的解决 自用的一台ThinkpadT490笔记本电脑 ,由于主板故障,不得不更换主板,通过某宝购置主板后进行了更换。 具体拆卸笔记本可搜索网络视频教程。 注意: 在更换主板时,注意先拍…...

项目-苍穹外卖(十七) Apache POI+导出数据

一、介绍 二、入门案例 package com.sky.test;import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File; import java.io.FileNotFoundException; import jav…...

蓝桥杯单片机刷题——E2PROM记录开机次数

设计要求 使用E2PROM完成数据记录功能&#xff0c;单片机复位次数记录到E2PROM的地址0中。每复位一次数值加1&#xff0c;按下按键S4&#xff0c;串口发送复位次数。串口发送格式如下&#xff1a; Number&#xff1a;1 备注&#xff1a; 单片机IRC振荡器频率设置为12MHz。 …...

聚合根的特性

聚合根的特性 聚合根是实体&#xff0c;拥有实体的业务属性和行为&#xff0c;同时也是聚合的管理者&#xff0c;负责协调聚合内的实体和值对象&#xff0c;按照固定的业务规则&#xff0c;完成业务逻辑。 聚合根是聚合对外唯一的接口人&#xff0c;聚合之间以聚合根ID关联的方…...

基于盛科CTC7132交换机核心模块

简介 基于盛科CTC7132 SOC方案构建&#xff0c;通过板对板高速连接器引出32路10G SerDes接口、1路PCIex1、2路管理SGMII接口、3路Uart接口&#xff08;1路调试串口2路功能串口&#xff09;、4路I2C接口(2路SOC部分2路PPU部分)、5路SMI接口&#xff08;1路管理口4路业务口&…...

How to install OpenJ9 JDK 17 on Ubuntu 24.04

概述 OpenJ9 是一款由 IBM 开发并开源的 Java 虚拟机&#xff08;JVM&#xff09;&#xff0c;现由 ​Eclipse 基金会管理&#xff08;名为 ​Eclipse OpenJ9&#xff09;。它旨在提供高性能、低内存消耗和快速启动时间&#xff0c;特别适用于云原生和容器化环境。 关键特性 …...

【即插即用涨点模块-卷积】SPDConv空间深度卷积,助力小目标与低分辨有效涨点【附源码+注释】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

全流程剖析需求开发:打造极致贴合用户的产品

全流程剖析需求开发&#xff1a;打造极致贴合用户的产品 一、需求获取&#xff08;一&#xff09;与用户沟通&#xff08;二&#xff09;观察用户工作&#xff08;三&#xff09;收集现有文档 二、需求分析&#xff08;一&#xff09;提炼关键需求&#xff08;二&#xff09;建…...

《Python Web网站部署应知应会》No4:基于Flask的调用AI大模型的高性能博客网站的设计思路和实战(上)

基于Flask的调用AI大模型的高性能博客网站的设计思路和实战&#xff08;上&#xff09; 摘要 本文详细探讨了一个基于Flask框架的高性能博客系统的设计与实现&#xff0c;该系统集成了本地AI大模型生成内容的功能。我们重点关注如何在高并发、高负载状态下保持系统的高性能和…...

使用 Docker Compose 在单节点部署多容器

Docker Compose 是什么 Docker Compose 是一个用于运行多容器应用的工具, 通过一个docker-compose.yml文件, 配置应用的服务、网络和卷&#xff0c;然后使用简单的命令启动或停止所有服务 为什么需要 Docker Compose 当你有一个包含多个相互依赖的容器应用时&#xff0c;手动…...

STM32_HAL开发环境搭建【Keil(MDK-ARM)、STM32F1xx_DFP、 ST-Link、STM32CubeMX】

安装Keil(MDK-ARM)【集成开发环境IDE】 我们会在Keil(MDK-ARM)上去编写代码、编译代码、烧写代码、调试代码。 Keil(MDK-ARM)的安装方法&#xff1a; 教学视频的第02分03秒开始看。 安装过程中请修改一下下面两个路径&#xff0c;避免占用C盘空间。 Core就是Keil(MDK-ARM)的…...

在 React 中,组件之间传递变量的常见方法

目录 1. **通过 Props 传递数据**2. **通过回调函数传递数据**3. **通过 Context API 传递数据**4. **通过 Redux 管理全局状态**5. **通过事件总线&#xff08;如 Node.js 的 EventEmitter&#xff09;**6. **通过 Local Storage / Session Storage**7. **通过 URL 查询参数传…...

拦截器和过滤器详解

在 Java Web 开发中&#xff0c;拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;是两种常见的请求处理机制&#xff0c;它们用于对请求和响应进行预处理和后处理 1. 过滤器&#xff08;Filter&#xff09; 1.1 作用 Filter 主要用于对 请求…...