c++可变参数详解

devtools/2025/2/3 7:23:50/

目录

引言

 库的基本功能 

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.ppmy.cn/devtools/155658.html

相关文章

Flask数据的增删改查(CRUD)_flask删除数据自动更新

查询年龄小于17的学生信息 Student.query.filter(Student.s_age < 17) students Student.query.filter(Student.s_age.__lt__(17))模糊查询&#xff0c;使用like&#xff0c;查询姓名中第二位为花的学生信息 like ‘_花%’,_代表必须有一个数据&#xff0c;%任何数据 st…

人工智能在计算机视觉中的应用与创新发展研究

一、引言 1.1 研究背景与意义 1.1.1 研究背景 在当今数字化与智能化飞速发展的时代&#xff0c;人工智能已成为推动各领域变革的核心力量&#xff0c;而计算机视觉作为人工智能领域中极具活力与潜力的重要分支&#xff0c;正发挥着日益关键的作用。计算机视觉旨在赋予计算机…

网络安全技术简介

网络安全技术简介 随着信息技术的迅猛发展&#xff0c;互联网已经成为人们日常生活和工作中不可或缺的一部分。与此同时&#xff0c;网络安全问题也日益凸显&#xff0c;成为全球关注的焦点。无论是个人隐私泄露、企业数据被盗取还是国家信息安全受到威胁&#xff0c;都与网络…

【react+redux】 react使用redux相关内容

首先说一下&#xff0c;文章中所提及的内容都是我自己的个人理解&#xff0c;是我理逻辑的时候&#xff0c;自我说服的方式&#xff0c;如果有问题有补充欢迎在评论区指出。 一、场景描述 为什么在react里面要使用redux&#xff0c;我的理解是因为想要使组件之间的通信更便捷…

一文讲解Java中的BIO、NIO、AIO之间的区别

BIO、NIO、AIO是Java中常见的三种IO模型 BIO&#xff1a;采用阻塞式I/O模型&#xff0c;线程在执行I/O操作时被阻塞&#xff0c;无法处理其他任务&#xff0c;适用于连接数比较少的场景&#xff1b;NIO&#xff1a;采用非阻塞 I/O 模型&#xff0c;线程在等待 I/O 时可执行其…

探索数学:从起源到未来的无尽旅程

数学的定义与本质 数学&#xff0c;这门古老而又充满魅力的学科&#xff0c;自人类文明诞生之初便如影随形。然而&#xff0c;要精准地定义数学并非易事&#xff0c;不同的学者从各自的视角出发&#xff0c;给出了多样的阐释。 亚里士多德将数学定义为 “数量科学”&#xff…

课题介绍:基于惯性与单目视觉信息融合的室内微小型飞行器智能自主导航研究

室内微小型飞行器在国防、物流和监测等领域中应用广泛&#xff0c;但在复杂的非合作环境中实时避障和导航仍面临诸多挑战。由于微小型飞行器的载荷和能源限制&#xff0c;迫切需要开发高效的智能自主导航系统。本项目旨在研究基于惯性导航与单目视觉信息融合的技术&#xff0c;…

【leetcode100】路径总和Ⅲ

1、题目描述 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点…