如何使预处理器宏贪婪
How to make a preprocessor macro greedy?
我们有以下预处理器宏。它用于帮助Doxygen文档,因为Doxygen在C++和一些模板类型defs:方面存在问题
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
#endif
当X
是非模板或只有一个模板参数时,它非常有效。但是,如果X
是一个具有多个参数的模板:
DOCUMENTED_TYPEDEF(Foo<R,S>,Bar);
然后它会导致编译错误,因为字符串被拆分为Foo<R
和S>,Bar
(并且它不会生成文档)。
如何使预处理器宏变得贪婪?
你不会喜欢这样的:
#define COMMA ,
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
#endif
DOCUMENTED_TYPEDEF(Foo<R COMMA S>,Bar)
测试:
$gcc-E逗号宏.c#1"逗号宏.c"#1"<内置>"#1"<命令行>"#1"逗号宏.c"#9"逗号宏.c"typedef Foo<R、S>酒吧
在进行任何替换之前,都会分析宏参数列表中的括号和逗号。然后COMMA
被替换为x
变元,x
被替换为宏体。到那时,争论就结束了;CCD_ 8被逗号标点符号替换是不相关的。但是,逗号将分隔该宏生成的任何宏调用中出现的参数,因此,如果必须保护这些参数,则需要更疯狂的方法。
您可以将COMMA
隐藏在类似函数的宏后面,比如PAIR
:
#define COMMA ,
#define PAIR(A, B) A COMMA B
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
#endif
DOCUMENTED_TYPEDEF(PAIR(Foo<R, S>), Bar)
乍一看,它更有吸引力,但可能也有缺点。这更令人困惑。读者想知道,PAIR
背后有语义吗?而COMMA
看起来太迟钝了,没有语义,而且它的目的对于任何因与预处理器斗争而留下战斗创伤的人来说都可能是显而易见的。
关于PAIR
,我们可以隐藏它,并最终得到Zwol的答案中的语法。但我们需要DOCUMENTED_TYPEDEF
的多种变体。
此外,顺便说一句,让我们把无用的COMMA
放在宏的右侧:
#define PAIR(A, B) A, B
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF_2(x2, y) class y : public PAIR x2 {};
#else
# define DOCUMENTED_TYPEDEF_2(x2, y) typedef PAIR x2 y;
#endif
DOCUMENTED_TYPEDEF_2((<R, S>), Bar)
$gcc-std=c90-E-Wall-迂腐的逗号宏.c#1"逗号宏.c"#1"<内置>"#1"<命令行>"#1"逗号宏.c"#11"逗号宏.c"typedef<R、 S>酒吧
这看起来可能适用于C99风格的可变宏。然而,这可能违反了评论中讨论的可移植性要求,更不用说这是C++了。为了未来的访客:
#define PNEUMATIC_COMMA_GUN(A, ...) A, ## __VA_ARGS__
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(xv, y) class y : public PNEUMATIC_COMMA_GUN xv {};
#else
# define DOCUMENTED_TYPEDEF(xv, y) typedef PNEUMATIC_COMMA_GUN xv y;
#endif
DOCUMENTED_TYPEDEF((<R, S, T, L, N, E>), Bar)
$gcc-std=c99-E-Wall-迂腐的逗号宏.c#1"逗号宏.c"#1"<内置>"#1"<命令行>"#1"逗号宏.c"#9"逗号宏.c"typedef<R、 S、T、L、N、E>酒吧
无法更改预处理器解析宏参数的方式。不在括号内的逗号总是分隔宏参数。
您可能能够做的是
DOCUMENTED_TYPEDEF((Foo<R,S>), Bar);
当然,只有当内部圆括号出现在宏的展开中时,这才有效。我不记得这会不会在你所展示的环境中造成问题。
如果需要C99可变宏是可以的,您可以使用它们来去掉额外的括号:
#define STRIP_PARENS(...) __VA_ARGS__
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public STRIP_PARENS x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef STRIP_PARENS x y;
#endif
DOCUMENTED_TYPEDEF((Foo<R,S>), Bar);
但现在总是必须在DOCUMENTED_TYPEDEF的第一个参数周围多放一对括号。
- #定义c-预处理器常量..我做错了什么
- 预处理器:插入结构名称中的前一个行号
- 如何在c++中实现处理器调度模拟器
- C/C++预处理器是否可以检测一些编译器选项
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 在clang++预处理器中确定gcc工具链版本
- 不同/较旧的处理器运行c++代码的方式是否不同
- 用于交叉编译和CMake的预处理器宏的单元测试
- 有没有办法在从编译器获取参数时避免预处理器宏?
- 如何比较两个同名的预处理器宏?
- 从预处理器获取 Windows 版本(C++ Win32)
- 如何摆脱为条件编译定义预处理器宏的需要?
- C 预处理器 - 现有定义的预置路径
- VS2015 预处理器定义与点
- 不带预处理器的调用方法/文件的文件名/行号
- 贪婪算法编号列表
- 获取文件数据预处理器宏
- 有没有办法在 c++ 中拥有条件预处理器
- 如何在编译时定义C++预处理器指令的值?
- 如何使预处理器宏贪婪