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

相关推荐
Dovis(誓平步青云)1 分钟前
基于探索C++特殊容器类型:容器适配器+底层实现原理
开发语言·c++·queue·适配器·stack
feiyangqingyun11 分钟前
全网唯一/Qt结合ffmpeg实现手机端采集摄像头推流到rtsp或rtmp/可切换前置后置摄像头/指定分辨率帧率
qt·智能手机·ffmpeg
随意02328 分钟前
Qt 事件
开发语言·qt
鸥梨菌Honevid35 分钟前
Qt自定义控件(1)——QPaintEvent
开发语言·qt
pipip.2 小时前
UDP————套接字socket
linux·网络·c++·网络协议·udp
孞㐑¥6 小时前
Linux之Socket 编程 UDP
linux·服务器·c++·经验分享·笔记·网络协议·udp
水木兰亭9 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
CoderCodingNo10 小时前
【GESP】C++四级考试大纲知识点梳理, (7) 排序算法基本概念
开发语言·c++·排序算法
秋风&萧瑟12 小时前
【C++】C++中的友元函数和友元类
c++
梁诚斌12 小时前
使用OpenSSL接口读取pem编码格式文件中的证书
开发语言·c++