C++宏定义中可变参数列表__VA_ARGS__ 及 QT 提供的宏 QT_OVERLOADED_MACRO

1. 基本用法

VA_ARGS 是 C/C++ 中的预定义宏,用于在宏定义中表示可变参数列表(Variadic Arguments),需与省略号 ... 配合使用。其核心作用是将宏调用中的可变参数原样传递给展开后的代码。

复制代码
#define LOG(format, ...) printf(format, __VA_ARGS__)
LOG("Value: %d", 42);  // 展开为 printf("Value: %d", 42)

注意: VA_ARGS 无法直接访问可变参数列表内的单个参数,也无法直接知道传递了多少个参数。

2. ##的使用

VA_ARGS 为空时,上面的用法会出现错误,因为format的后面多了一个逗号。为了避免语法错误需要使用 ## 告诉编译器,当可变参数为空时自动去掉前面的逗号。

复制代码
#define LOG(format, ...) printf(format, ##__VA_ARGS__)
LOG("Value: %d", 42);  // 展开为 printf("Value: %d", 42)
LOG("some message");  // 展开为 printf("some message")

3. 获取可变参数的个数

常见的方式如下,parameterNum()得出了输入的参数数目。

复制代码
#define get5th(a1, a2, a3, a4, a5, ...) a5
// ... getnth(a1, a2, a3, ... , an, ...) an
#define parameterNum(...) get5th(__VA_ARGS__, 4, 3, 2, 1)

parameterNum(a)
//get5th(a, 4, 3, 2, 1)
//1

parameterNum(a, b, c)
//get5th(a, b, c, 4, 3, 2, 1)
//3

但是当__VA_ARGS__参数数目为0时会出现多余的逗号,计算结果还是1,需要进一步处理。

复制代码
#define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...) N
#define COUNT_ARGS(...) __COUNT_ARGS(, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

COUNT_ARGS(a)
//__COUNT_ARGS(a, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
//1

COUNT_ARGS()
//__COUNT_ARGS(, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
//0

4. QT 预置的宏

QT 在文件 qoverload.h 中提供了对可变参数的宏,单可变参数数量小于10个时可以直接使用QT提供的宏 QT_OVERLOADED_MACRO(MACRO, ...)。

复制代码
#define QT_VA_ARGS_CHOOSE(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N
#define QT_VA_ARGS_EXPAND(...) __VA_ARGS__ // Needed for MSVC
#define QT_VA_ARGS_COUNT(...) QT_VA_ARGS_EXPAND(QT_VA_ARGS_CHOOSE(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define QT_OVERLOADED_MACRO_EXPAND(MACRO, ARGC) MACRO##_##ARGC
#define QT_OVERLOADED_MACRO_IMP(MACRO, ARGC) QT_OVERLOADED_MACRO_EXPAND(MACRO, ARGC)
#define QT_OVERLOADED_MACRO(MACRO, ...) QT_VA_ARGS_EXPAND(QT_OVERLOADED_MACRO_IMP(MACRO, QT_VA_ARGS_COUNT(__VA_ARGS__))(__VA_ARGS__))

用法示例:

复制代码
#define sum_1(num1) num1
#define sum_2(num1, num2) num1 + num2
#define sum_3(num1, num2, num3) num1 + num2 + num3
#define sum_4(num1, num2, num3, num4) num1 + num2 + num3 + num4
#define sum_5(num1, num2, num3, num4, num5) num1 + num2 + num3 + num4 + num5

#define sum(...) QT_OVERLOADED_MACRO(sum,  __VA_ARGS__) 

int x = sum(1,2);
//int x = 1+2;
QString s = sum("a", "b");
// QString s = "a" +"b";

参考:
C语言可变参数宏定义方法
【Just For Fun】C - 宏开发 - 选取第 n 项参数、按照参数数目展开不同的宏、缺陷
【宏定义】------获取可变参数宏的参数数量

相关推荐
ysa05103035 分钟前
虚拟位置映射(标签鸽
数据结构·c++·笔记·算法
m0_748248021 小时前
C++中的位运算符:与、或、异或详解
java·c++·算法
老歌老听老掉牙1 小时前
解决 PyQt5 中 sipPyTypeDict() 弃用警告的完整指南
python·qt
草莓熊Lotso2 小时前
C++ 方向 Web 自动化测试实战:以博客系统为例,从用例到报告全流程解析
前端·网络·c++·人工智能·后端·python·功能测试
共享家95272 小时前
LRU 缓存的设计与实现
开发语言·c++
草莓熊Lotso3 小时前
Linux 基础开发工具入门:软件包管理器的全方位实操指南
linux·运维·服务器·c++·人工智能·网络协议·rpc
小龙报3 小时前
算法通关指南:数据结构和算法篇 --- 队列相关算法题》--- 1. 【模板】队列,2. 机器翻译
c语言·开发语言·数据结构·c++·算法·学习方法·visual studio
晨非辰3 小时前
【数据结构初阶】--从排序算法原理分析到代码实现操作,参透插入排序的奥秘!
c语言·开发语言·数据结构·c++·算法·面试·排序算法
2301_795167207 小时前
玩转Rust高级应用 如何避免对空指针做“解引用”操作,在C/C++ 里面就是未定义行为
c语言·c++·rust
不染尘.12 小时前
2025_11_7_刷题
开发语言·c++·vscode·算法