字符串的递归预处理器宏
Recursive preprocessor macro for strings
我有一些代码大部分需要 Unicode 字符串,但我想让它成为条件(即,TEXT("string")
扩展到 L"string"
或 "string"
,具体取决于设置(。对于这些,我使用宏:
#ifdef _UNICODE
# define VSTR(str) L##str
#else
# define VSTR(str) str
#endif
这样做的主要复杂性是 printf 格式字符串,它分别对相同编码和其他编码字符串使用 %s
和 %S
。一些字符串来自类似的条件 API(TCHAR
和类似(,而一些来自集合 API(主要是仅 C 字符串(。使用_tprintf
和 family 时,所使用的函数可能会有所不同,使%s
和%S
条件也各不相同,并且可能需要翻转它们。为了解决这个问题,我为适当的格式元素定义了宏:
#ifdef _UNICODE
# define VPFCSTR(str) "%S"
# define VPFWSTR(str) "%s"
# define VPFTSTR(str) VPFWSTR(str)
#else
# define VPFCSTR(str) "%s"
# define VPFWSTR(str) "%S"
# define VPFTSTR(str) VPFCSTR(str)
#else
现在,这一切都工作正常,但强制语法:
VSTR("Beginning of a format string, with a string '") VPFTSTR VSTR("' included.")
我希望能够使用这样的语法:
VSTR("Beginning of a format string, with a string '", VPFTSTR, "' included.")
对于 Unicode,这需要扩展到:
L"Beginning of a format string, with a string '" L"%s" L"' included."
唯一的复杂之处在于参数数量可变,所有这些参数都需要以相同的方式进行转换(如有必要,逐个转换(。
我的第一个想法是使用 __VA_ARGS__
来处理这个问题,使用空参数,例如:
VASTR(str, ...) VSTR(str) VASTR(__VA_ARGS__)
不幸的是,由于宏不能在它们自己的定义中使用,所以这失败了。然后我尝试了一个代理:
VASTR2(...) VASTR(__VA_ARGS__)
VASTR(str, ...) VSTR(str) VASTR2(__VA_ARGS__)
代理方法似乎也不起作用。
有没有办法处理在(其他(宏的每个参数上运行相同的宏,这需要可变数量的参数?或者,如果没有,是否有等效物?如果特定于编译器,则首选 MSVC10,但任何内容都值得关注。
递归宏扩展在 C/C++ 中是不可能的。
不确定,但 C++0x 允许您省略字符串文字连接的编码前缀。因此,您可以尝试将宏设计为仅将L
附加到第一个字符串文本,并按如下方式使用它:
VSTR("Beginning of a format string, with a string '" VPFTSTR "' included.")
如果我错了,请纠正我。
上。
一个类似的 Unicode 相关问题:当存在修饰符(L、u8 等(时,相邻字符串文字连接会发生什么
使用 Boost.Preprocessor 库和这些附加宏,您可以将 VSTR 宏应用于每个参数:
//Your VSTR macro for one argument
#define VSTR_EACH(str) ...
/**
* PP_NARGS returns the number of args in __VA_ARGS__
*/
#define PP_NARGS(...)
PP_DETAIL_NARG((__VA_ARGS__,PP_DETAIL_RSEQ_N()))
#define PP_DETAIL_NARG(args)
PP_DETAIL_ARG_N args
#define PP_DETAIL_ARG_N(
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10,
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,
_61,_62,_63,N,...) N
#define PP_DETAIL_RSEQ_N()
63,62,61,60,
59,58,57,56,55,54,53,52,51,50,
49,48,47,46,45,44,43,42,41,40,
39,38,37,36,35,34,33,32,31,30,
29,28,27,26,25,24,23,22,21,20,
19,18,17,16,15,14,13,12,11,10,
9,8,7,6,5,4,3,2,1,0
//Convert agruments list to a BOOST_PP_SEQ so we can iterate over it
//This is two macros in order to avoid the bug in MSVC compilers
#define DETAIL_PP_ARGS_TO_SEQ(size, tuple) BOOST_PP_TUPLE_TO_SEQ(size, tuple)
#define PP_ARGS_TO_SEQ(...) DETAIL_PP_ARGS_TO_SEQ(PP_NARGS(__VA_ARGS__), (__VA_ARGS__))
//The macro used inside of BOOST_PP_SEQ_FOR_EACH
#define VSTR_SEQ_EACH(t, data, x) VSTR_EACH(x)
#define VSTR(...) BOOST_PP_SEQ_FOR_EACH(VSTR_SEQ_EACH, ~, PP_ARGS_TO_SEQ(__VA_ARGS__))
- 错误:无效的预处理指令 #i 的意思是 #if?
- C++预处理会生成变量成员、资源库和映射
- 使用预处理指令检查是否包含标头?
- 预处理的 C/C++ 文件是否特定于计算机?
- 使用 GCC 对 C 文件进行部分预处理(不删除 "define" 指令)
- 在 CPLEX 中求解线性规划,无需剪切和预处理
- CPP -D 选项,用于预处理 Fortran 代码
- 错误:粘贴"tmp_UINT"和"+"未提供有效的预处理令牌
- 任务计划程序库的预处理不起作用 - 多定义错误
- Eclipse 问题 - 编译期间不考虑 .c 和 .cpp 文件中定义的预处理
- 使用python预处理后,C++(opencv)中的垫子类型数据与image_to_array相同
- Howo 使用 cl 预处理为 masm 组装生成一个单独的文件
- 我有一个预处理的 C/C++ 源文件 (cacti.i).如何从这个 .i 文件生成可执行二进制文件,以便我可以像 ./
- 如何使用Visual Studio C/C++编译器(cl.exe)来预处理我的objective-C代码
- 是具有预处理前分支实现的结构违反ODR
- 与不完整的Cholesky预处理的共轭梯度返回特征库的意外错误
- Visual Studio C - 无法输出预处理文件
- 在海湾合作委员会中加快宏观预处理的任何方法
- 所有结构成员的预处理器批处理
- 当头文件被预处理时是否有一个预处理器选项显示?