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

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.kler.cn/a/530013.html

相关文章:

  • 解决国内服务器 npm install 卡住的问题
  • python学opencv|读取图像(五十二)使用cv.matchTemplate()函数实现最佳图像匹配
  • 【Rust自学】15.5. Rc<T>:引用计数智能指针与共享所有权
  • 具身智能体空间感知基础!ROBOSPATIAL:评测并增强2D和3D视觉语言模型空间理解水平
  • (动态规划基础 打家劫舍)leetcode 198
  • 步入响应式编程篇(三)之spring webFlux与R2DBC
  • 前端知识速记--HTML篇:src和href
  • 【4】阿里面试题整理
  • Joplin 插件在Vscode中无法显示图片
  • UE5 蓝图学习计划 - Day 6:角色蓝图
  • Observability:实现 OpenTelemetry 原生可观察性的商业价值
  • Python面试宝典13 | Python 变量作用域,从入门到精通
  • 大型云平台虚拟化技术介绍
  • 搬迁至bilibili声明
  • 在CentOS服务器上部署DeepSeek R1
  • 使用 PyTorch 实现逻辑回归并评估模型性能
  • C#魔法秘籍:委托与事件,开启多态回调与消息派对之旅
  • openRv1126 AI算法部署实战之——Tensorflow模型部署实战
  • SQLite Update 语句详解
  • 我用Ai学Android Jetpack Compose之Card
  • Chapter2 Amplifiers, Source followers Cascodes
  • springCload快速入门
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.6 广播机制核心算法:维度扩展的数学建模
  • 亚博microros小车-原生ubuntu支持系列:19 nav2 导航
  • priority_queue
  • Kanass快速安装配置教程(入门级)