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 项参数、按照参数数目展开不同的宏、缺陷
【宏定义】------获取可变参数宏的参数数量

相关推荐
byte轻骑兵21 分钟前
【C++重载操作符与转换】转换与继承
开发语言·c++
筏.k1 小时前
C++ asio网络编程(4)异步读写操作及注意事项
服务器·网络·c++
炬火初现1 小时前
Qt 的原理及使用(1)——qt的背景及安装
开发语言·qt
weixin_1101 小时前
Qt 无边框窗口,支持贴边分屏
c++·qt
gaoenyang7605251 小时前
QT Creator配置Kit
开发语言·qt
Cuit小唐1 小时前
C++ 组合模式详解
开发语言·c++·组合模式
hallo-ooo2 小时前
【C/C++】const关键词及拓展
c语言·c++
代码AC不AC2 小时前
【C++】模板初阶
开发语言·c++·学习分享·技术交流·模板初阶
阿沁QWQ2 小时前
C语言中的文本读写和二进制读写接口
开发语言·c++·算法
Ronin3053 小时前
【C++】16.继承
开发语言·c++