jww*_*jww 3 c++ macros doxygen greedy c-preprocessor
我们有以下预处理器宏。它用于帮助Doxygen文档,因为Doxygen在使用C ++和某些模板typedef时遇到了麻烦:
#if defined(DOXYGEN_PROCESSING)
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
#else
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
#endif
Run Code Online (Sandbox Code Playgroud)
如果X是非模板或只有一个模板参数,则效果很好。但是,如果X是具有多个参数的模板:
DOCUMENTED_TYPEDEF(Foo<R,S>,Bar);
Run Code Online (Sandbox Code Playgroud)
然后,由于将字符串拆分为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)
Run Code Online (Sandbox Code Playgroud)
测试:
$ gcc -E逗号-c #1“ comma-macro.c” #1“ <内置>” #1“ <命令行>” #1“ comma-macro.c” #9“ comma-macro.c” typedef Foo <R,S>栏;
在进行任何替换之前,都会解析宏参数列表的括号和逗号。然后COMMA在x参数中被替换,并被x替换为宏体。那时,争论已经完成。COMMA替换为逗号标点符号并不重要。但是,该逗号将分隔在该宏生成的任何宏调用中出现的参数,因此,如果必须对其进行保护,则需要更疯狂的操作。
您可以将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)
Run Code Online (Sandbox Code Playgroud)
乍一看,它更具吸引力,但可能存在弊端。更加令人困惑。读者想知道,后面是否有语义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)
Run Code Online (Sandbox Code Playgroud)
$ gcc -std = c90 -E -Wall -pedantic逗号-macro.c #1“ comma-macro.c” #1“ <内置>” #1“ <命令行>” #1“ comma-macro.c” #11“ comma-macro.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)
Run Code Online (Sandbox Code Playgroud)
$ gcc -std = c99 -E -Wall -pedantic逗号-macro.c #1“ comma-macro.c” #1“ <内置>” #1“ <命令行>” #1“ comma-macro.c” #9“ comma-macro.c” typedef <R,S,T,L,N,E>条;