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

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对象的消耗


🦀🦀观看~~

相关文章:

  • 【Python】pillow库学习笔记3-Image.mode
  • canvas学习:如何绘制带孔洞的多边形
  • 详细存储与相关接口协议?
  • Vue项目的 Sass 全局基础样式格式化方案,包含常见元素的样式重置
  • 头歌实践教学平台--【数据库概论】--SQL
  • VUE3 路由配置
  • Apifox下载安装
  • 【C++】C++中的动态内存分配(new和delete)
  • 2025前端面试题(vue、react、uniapp、微信小程序、JS、CSS、其他)
  • 从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.2.1从零编写类GPT-2模型架构(规划模块与代码组织)
  • 详细介绍RECT结构体
  • 09_从经典论文入手Seq2Seq架构
  • spring-security原理与应用系列:核心过滤器
  • 设置 Ollama 模型下载位置
  • Spring 线程
  • 微信小程序如何接入直播功能
  • [leetcode]map的用法
  • SpringBoot-配置文件中敏感信息的加密保姆级教程
  • Solr-搜索引擎-入门到精通
  • Ubuntu与Windows之间相互复制粘贴的方法
  • 酒店网站 asp.net/百度官方版
  • 做ptt网站/成都全网营销推广
  • 电商网站推广渠道/免费发布广告信息平台
  • 企业公司网站建设方案/山东进一步优化
  • 政府网站建设长沙/投资网站建设方案
  • 有没有免费的推广网站/快速收录域名