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 项参数、按照参数数目展开不同的宏、缺陷
【宏定义】——获取可变参数宏的参数数量
C++宏定义中可变参数列表__VA_ARGS__ 及 QT 提供的宏 QT_OVERLOADED_MACRO的更多相关文章
- C语言 宏定义之可变参数
可变参数宏定义 C99编译器标准允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏.可变参数宏就像下面这个样子: #define dbgprint(. ...
- GNU中宏定义对可变参数的支持(引自百度)
http://zhidao.baidu.com/question/125413478.html 问:#define PDEBUG(fmt,args...) fprintf(stderr,fmt, ## ...
- C语言函数可变参数列表
C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏v ...
- C++可变参数列表处理宏va_list、va_start、va_end的使用
VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef _M_ALPHA typedef struct{ char* a0; /* ...
- 【转】C++可变参数列表处理宏va_list、va_start、va_end的使用
VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef _M_ALPHA typedef struct{ char* a0; /*po ...
- 可变参数列表---以dbg()为例
在UART驱动的drivers/serial/samsung.h中遇到如下定义: #ifdef CONFIG_SERIAL_SAMSUNG_DEBUG extern void printascii(c ...
- C语言中可变参数的原理——printf()函数
函数原型: int printf(const char *format[,argument]...) 返 回 值: 成功则返回实际输出的字符数,失败返回-1. 函数说明: 使用过C语言的人所再熟悉不过 ...
- define宏定义中的#,##,@#及\符号
define宏定义中的#,##,@#及\符号 在#define中,标准只定义了#和##两种操作.#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串. 1.# (string ...
- C语言可变参数在宏定义中的应用
在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用 ...
- Python学习笔记之7.5 - 定义有默认参数的函数》》》直接在函数定义中给参数指定一个默认值,默认参数的值应该是不可变的对象
问题: 你想定义一个函数或者方法,它的一个或多个参数是可选的并且有一个默认值. 解决方案: 定义一个有可选参数的函数是非常简单的,直接在函数定义中给参数指定一个默认值,并放到参数列表最后就行了.例如: ...
随机推荐
- mxGraph绘制机构图
简单介绍一下使用的依赖: JGraphX package JGraphX is a Java Swing diagramming (graph visualisation) library lic ...
- Kotlin:【定义类】field、计算属性、防态竞争条件
- python教程合集(更新中)
python教程目录 基础 hello world 变量 输入输出
- MySQL-8.0.20
版本: 8.0.20 操作: Centos 7 Linux 未介绍针对数据库的详细操作,如有需求请前往 第一章 MySQL的介绍及安装 1.介绍 1.1 数据库管理系统(DBMS) RDBMS : O ...
- hashmap为什么要引入红黑树?
在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依 ...
- tomcat启动时启动窗口出现乱码的解决方案
工具/原料 一台安装了tomcat的电脑 方法/步骤 先来看看问题(图示),在tomcat的启动窗口打印的启动信息中包含了大量的中文乱码,虽然这些对tomcat本身的使用没有任何影响,但却 ...
- autMan奥特曼机器人-内置wx机器人的相关说明
内置wx机器人的相关说明 内置wxbot机器人,经常有人说在群内无回复,做以下几个工作: 给群命名 通过机器人微信APP将此群加入到通讯录 重启autMan 内置微信机器人已经支持群名设置 例如转发时 ...
- Typecho 数据备份及程序升级详细步骤教程
数据库备份看自己,习惯性更新前都备份,出错直接滚回去 数据库备份 直接在宝塔数据库那个模块备份即可,备份完建议下载本地或者保存到OSS 备份网站文件 理论上只需要备份/usr/目录即可,因为这个目录包 ...
- pnpm : 无法加载文件 \AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本。
1. 安装pnpm npm install -g pnpm #安装 pnpm pnpm --version #查看pnpm版本 安装完成后查看版本时报错 pnpm : 无法加载文件 C:\Users\ ...
- 【由技及道】螺蛳壳里做道场-git仓库篇-gitlab-Vs-gitea【人工智障AI2077的开发日志001】
指令接收:「开始构建代码宇宙」 系统检测:需求模糊度99.9% 启动应急协议:构建最小可行性生态圈 核心组件锁定:代码基因库(人类称之为Git仓库) 需求分析:论人类语言的艺术性 人类指令翻译机 表面 ...