如何预处理__VA_ARGS__参数,实现bool转int后传入std::format?
解决方案
要实现对FORMAT_STRING可变参数的逐个预处理,在VS2019、C++20环境下可以通过模板函数+宏结合折叠表达式的方式完成,既不用逐个修改格式串,又能自动将bool类型参数转为int输出。
实现步骤
1. 定义参数预处理模板函数
用编译期判断的模板函数处理单个参数,针对bool类型做转换,其他参数原样转发:
#include <format> #include <type_traits> #include <iostream> using namespace std; template<typename T> auto fmt_preprocess(T&& arg) { if constexpr (std::is_same_v<std::remove_cvref_t<T>, bool>) { // 将bool转为int,模拟printf的%d输出效果 return static_cast<int>(std::forward<T>(arg)); } else { // 非bool参数直接转发 return std::forward<T>(arg); } }
2. 重定义FORMAT_STRING宏
利用C++20的折叠表达式,对每个可变参数逐个调用预处理函数:
#define FORMAT_STRING(formatStr, ...) \ std::format(formatStr, fmt_preprocess(__VA_ARGS__)...)
3. 测试验证
原代码无需修改格式串,直接运行即可得到目标输出:
int main() { cout << FORMAT_STRING("{} {} ...", true, "hello") << endl; // 输出:1 hello ... cout << FORMAT_STRING("{} {} ...", false, "world") << endl; // 输出:0 world ... }
原写法错误原因
你之前的宏定义FMT_ARG_PRE_PROCESS(##__VA_ARGS__)会把所有可变参数作为一个整体传入预处理宏,导致展开为int(true, "hello")——这是因为##__VA_ARGS__将多个参数合并成了一个参数列表,而非逐个处理。
替代方案:纯宏实现
如果更倾向于纯宏方案,可以用C++20的__VA_OPT__配合宏展开来逐个处理参数:
#define FMT_ARG_PRE_PROCESS(x) \ (std::is_same_v<std::remove_cvref_t<decltype(x)>, bool> ? static_cast<int>(x) : (x)) #define FORMAT_STRING(formatStr, ...) \ std::format(formatStr, \ __VA_OPT__(FMT_ARG_PRE_PROCESS(__VA_ARGS__) __VA_OPT__(,) ...))
这种方式同样能实现逐个参数预处理,但模板函数的方式类型安全性更高、可读性更好,更推荐使用。
内容的提问来源于stack exchange,提问作者hchlqlz
相关产品推荐
相关产品推荐

