c++可变参数详解

目录

引言

 库的基本功能 

va_start 宏:

va_arg 宏

va_end 宏

va_copy 宏

使用  处理可变参数代码

C++11可变参数模板

基本概念

sizeof... 运算符

包扩展


引言

        在C++编程中,处理不确定数量的参数是一个常见的需求。为了支持这种需求,C标准库提供了 <stdarg.h> 头文件,其中定义了一组宏和类型,用于处理不定参数函数。C++继承了C语言的可变参数机制,使用了stdarg.h提供的宏来处理不确定数量的参数。其原理基于栈的推入和弹出过程,不需要明确参数数量。此外,C++提供了可变参数机制,让我们能够创建接收任意数量参数的函数。这一特性在许多实际应用中非常有用,比如日志记录、函数重载等。

<stdarg.h> 库的基本功能 

<stdarg.h> 库包含以下主要部分:

va_start 宏:

用于初始化 va_list 变量,其基本语法如下:

void va_start(va_list ap, last);
  • apva_list 变量。
  • last:最后一个确定的参数,后面的参数是可变参数。

va_arg 宏

 va_arg 宏用于访问可变参数列表中的下一个参数,其基本语法如下:

type va_arg(va_list ap, type);
  • apva_list 变量。
  • type:要访问的参数的类型。

va_end 宏
 

  va_end 宏用于结束 va_list 变量的访问,其基本语法如下:

void va_end(va_list ap);
  •   ap:va_list 变量。


va_copy 宏

  va_copy 宏用于复制 va_list 变量,其基本语法如下:

void va_copy(va_list dest, va_list src);
  • dest:目标 va_list 变量。
  • src:源 va_list 变量。

使用 <stdarg.h> 处理可变参数代码

        示例中,print_args接收一个格式字符串,然后根据格式字符(i表示整数,d表示双精度浮点数)解析后面的参数。

#include <iostream>
#include <cstdarg>void print_args(const char* fmt, ...)
{va_list args;va_start(args, fmt);while (*fmt != '\0') {if (*fmt == 'i') {int i = va_arg(args, int);std::cout << "int: " << i << std::endl;} elseif (*fmt == 'd') {double d = va_arg(args, double);std::cout << "double: " << d << std::endl;}++fmt;}va_end(args);
}int main()
{print_args("ddii", 0.618,3.14, 7, 9);return 0;
}
//double: 0.618 double: 3.14 int: 7 int: 9

C++11可变参数模板

基本概念

        C++11通过模板提供了类型安全且灵活的可变参数机制。可以通过递归模板来处理不同类型的参数,避免了手动处理类型的麻烦。也就是支持可变数量参数的函数模板和类模板,可变数目的参数被称为参数包。

参数包有两种类型:

  • 模板参数包,表示零或多个模板参数,使用class...或typename...关键字声明。
  • 函数参数包,表示零个或多个函数参数,使用类型名后跟...表示。
template<class ...Arg> void Func(Arg... arg) {}
template<class ...Arg> void Func(Arg... arg) {}
template<class ...Arg> void Func(Arg... arg) {}

         我们用省略号...来指出一个模板参数或函数参数的表示一个包,在模板参数列表中,class...或typename...指出接下来的参数表示零或多个类型列表;在函数参数列表中,类型名后面跟...指出接下来表示零或多个形参对象列表。可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。

sizeof... 运算符

sizeof...运算符来计算参数包中参数的个数。

template <class ...Arg>
void PrintArgNum(Arg&&... arg)
{cout << sizeof...(arg)<<"个参数包" << endl;
}int main()
{double a = 3.14;PrintArgNum();PrintArgNum(a);//一个参数PrintArgNum(1, string("241564132"));//两个参数return 0;
}

        编译本质会结合引用折叠规则实例化出以下三个函数,在类型泛化基础上叠加了数量变化,让泛型编程更加灵活。

void Print();
void Print(double&& arg1);
void Print(int&& arg1, string&& arg2);

包扩展

        对于一个参数包,我们除了计算它的参数个数,还可以对它进行包扩展。我们还要提供用于每个扩展元素的模式,扩展一个包就是将他分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式的右边放省略号(...)来触发扩展操作。

//参数包是0个时,直接匹配这个函数
void ShowList()
{cout<< endl;
}template<class T,class ...Arg>
void ShowList(T&& val,Arg&&... arg)
{cout << val << endl;//arg是N个参数的参数包,调用Printf,参数包的第一个传给val,剩下N-1个传给参数包,ShowList(arg...);
}
template <class ...Arg>
void Print(Arg&&... arg)
{cout << sizeof...(arg)<<"个参数包" << endl;ShowList(arg...);
}int main()
{double x = 3.14;Print();Print(11.1);//一个参数Print(1, string("bjkbhv"));//两个参数Print(12.55, string("9jjug7"), x);//三个参数return 0;
}

        实际上是通过递归展开来实现的,当参数包为空时就会调用 void ShowList(),同时终止递归

递归时,T接受传来参数包的第一个参数类型,arg接受其余的参数类型,以此往复。

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

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

相关文章

w191教师工作量管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

Vuex状态管理

1、Vuex 是什么&#xff1f; Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 简单理解 Vuex可以帮我们管理全局的属性&#xff0c;并且是是响应式的&…

DBASE DBF数据库文件解析

基于Java实现DBase DBF文件的解析和显示 JDK19编译运行&#xff0c;实现了数据库字段和数据解析显示。 首先解析数据库文件头代码 byte bytes[] Files.readAllBytes(Paths.get(file));BinaryBufferArray bis new BinaryBufferArray(bytes);DBF dbf new DBF();dbf.VersionN…

亚博microros小车-原生ubuntu支持系列:20 ROS Robot APP建图

依赖工程 新建工程laserscan_to_point_publisher src/laserscan_to_point_publisher/laserscan_to_point_publisher/目录下新建文件laserscan_to_point_publish.py #!/usr/bin/env python3import rclpy from rclpy.node import Node from geometry_msgs.msg import PoseStam…

冷启动+强化学习:DeepSeek-R1 的原理详解——无需监督数据的推理能力进化之路

本文基于 DeepSeek 官方论文进行分析,论文地址为:https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf 有不足之处欢迎评论区交流 原文翻译 在阅读和理解一篇复杂的技术论文时,逐字翻译是一个重要的步骤。它不仅能帮助我们准确把握作者的原意,还能为后续…

优选算法的灵动之章:双指针专题(一)

个人主页&#xff1a;手握风云 专栏&#xff1a;算法 一、双指针算法思想 双指针算法主要用于处理数组、链表等线性数据结构中的问题。它通过设置两个指针&#xff0c;在数据结构上进行遍历和操作&#xff0c;从而实现高效解决问题。 二、算法题精讲 2.1. 查找总价格为目标值…

数据结构之栈和队列(超详解)

文章目录 概念与结构栈队列 代码实现栈栈是否为空&#xff0c;取栈顶数据、栈的有效个数 队列入队列出队列队列判空&#xff0c;取队头、队尾数据&#xff0c;队列的有效个数 算法题解有效的括号用队列实现栈用栈实现队列复用 设计循环队列数组结构实现循环队列构造、销毁循环队…

解析 Oracle 中的 ALL_SYNONYMS 和 ALL_VIEWS 视图:查找同义词与视图的基础操作

目录 前言1. ALL_SYNONYMS 视图2. ALL_VIEWS 视图3. 扩展 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. ALL_SYNONYMS 视图 在 Oracle 数据库中&#xff0c;同义词&#xff08;Synonym&#xff09;是对数…

DeepSeek-R1 本地部署教程(超简版)

文章目录 一、DeepSeek相关网站二、DeepSeek-R1硬件要求三、本地部署DeepSeek-R11. 安装Ollama1.1 Windows1.2 Linux1.3 macOS 2. 下载和运行DeepSeek模型3. 列出本地已下载的模型 四、Ollama命令大全五、常见问题解决附&#xff1a;DeepSeek模型资源 一、DeepSeek相关网站 官…

【C语言入门】解锁核心关键字的终极奥秘与实战应用(二)

目录 一、sizeof 1.1. 作用 2.2. 代码示例 二、const 2.1. 作用 2.2. 代码示例 三、signed 和 unsigned 3.1. 作用 3.2. 代码示例 四、struct、union、enum 4.1. struct&#xff08;结构体&#xff09; 4.1.1. 作用 4.1.2. 代码示例 4.2. union&#xff08;联合…

如何确认Linux嵌入式系统的触摸屏对应的是哪个设备文件?如何查看系统中所有的输入设备?输入设备的设备文件有什么特点?

Linux嵌入式系统的输入设备的设备文件有什么特点&#xff1f; 在 Linux 中&#xff0c;所有的输入设备&#xff08;如键盘、鼠标、触摸屏等&#xff09;都会被内核识别为 输入事件设备&#xff0c;并在 /dev/input/ 目录下创建相应的 设备文件&#xff0c;通常是&#xff1a; …

ESP32-c3实现获取土壤湿度(ADC模拟量)

1硬件实物图 2引脚定义 3使用说明 4实例代码 // 定义土壤湿度传感器连接的模拟输入引脚 const int soilMoisturePin 2; // 假设连接到GPIO2void setup() {// 初始化串口通信Serial.begin(115200); }void loop() {// 读取土壤湿度传感器的模拟值int sensorValue analogRead…

Hive:窗口函数(1)

窗口函数 窗口函数OVER()用于定义一个窗口&#xff0c;该窗口指定了函数应用的数据范围 对窗口数据进行分区 partition by 必须和over () 一起使用, distribute by经常和sort by 一起使用,可以不和over() 一起使用.DISTRIBUTE BY决定了数据如何分布到不同的Reducer上&#xf…

【react-redux】react-redux中的 useDispatch和useSelector的使用与原理解析

一、useSelector 首先&#xff0c;useSelector的作用是获取redux store中的数据。 下面就是源码&#xff0c;感觉它的定义就是首先是createSelectorHook这个方法先获得到redux的上下文对象。 然后从上下文对象中获取store数据。然后从store中得到选择的数据。 2、useDispatc…

java异常处理——try catch finally

单个异常处理 1.当try里的代码发生了catch里指定类型的异常之后&#xff0c;才会执行catch里的代码&#xff0c;程序正常执行到结尾 2.如果try里的代码发生了非catch指定类型的异常&#xff0c;则会强制停止程序&#xff0c;报错 3.finally修饰的代码一定会执行&#xff0c;除…

传输层协议 UDP 与 TCP

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; 前置复盘&#x1f98b; 传输层&#x1f98b; 再谈端口号&#x1f98b; 端口号范围划分&#x1f98b; 认识知名端口号 (Well-Know Port Number) 二&#xf…

The Simulation技术浅析(三):数值方法

The Simulation ,通常涉及使用数值方法对物理、工程或金融等领域的问题进行建模和求解。数值方法是解决复杂数学问题的关键技术,常见的数值方法包括 有限差分法(FDM)、有限元法(FEM) 和 蒙特卡洛方法(Monte Carlo Method)。 1. 有限差分法(FDM) 有限差分法是一种用于…

深度学习-98-大语言模型LLM之基于langchain的代理create_react_agent工具

文章目录 1 Agent代理1.1 代理的分类1.2 ReAct和Structured chat2 代理应用ReAct2.1 创建工具2.1.1 嵌入模型2.1.2 创建检索器2.1.3 测试检索结果2.1.4 创建工具列表2.2 初始化大模型2.3 创建Agent2.4 运行Agent3 参考附录1 Agent代理 Agent代理的核心思想是使用语言模型来选择…

小试牛刀,AI技术实现高效地解析和转换多种文档格式

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据、人工智能领域创作者。目前从事python全栈、爬虫和人工智能等相关工作&#xff0c;主要擅长领域有&#xff1a;python…

WPF进阶 | WPF 动画特效揭秘:实现炫酷的界面交互效果

WPF进阶 | WPF 动画特效揭秘&#xff1a;实现炫酷的界面交互效果 前言一、WPF 动画基础概念1.1 什么是 WPF 动画1.2 动画的基本类型1.3 动画的核心元素 二、线性动画详解2.1 DoubleAnimation 的使用2.2 ColorAnimation 实现颜色渐变 三、关键帧动画深入3.1 DoubleAnimationUsin…