C++ 如何使预处理器宏贪婪?

C++ 如何使预处理器宏贪婪?,c++,macros,c-preprocessor,doxygen,greedy,C++,Macros,C Preprocessor,Doxygen,Greedy,我们有以下预处理器宏。它用于帮助doxGEN文档,因为doxGEN对C++和一些模板类型DEFS:< /P>有困难。 #如果已定义(氧气处理) #定义文档化的_TYPEDEF(x,y)类y:public x{}; #否则 #定义文件化的_TYPEDEF(x,y)TYPEDEF x y; #恩迪夫 当X是非模板参数或只有一个模板参数时,它非常有效。但是,如果X是具有多个参数的模板: DOCUMENTED_TYPEDEF(Foo,Bar); 然后它会导致编译错误,因为字符串被拆分为Foo,Bar

我们有以下预处理器宏。它用于帮助doxGEN文档,因为doxGEN对C++和一些模板类型DEFS:< /P>有困难。
#如果已定义(氧气处理)
#定义文档化的_TYPEDEF(x,y)类y:public x{};
#否则
#定义文件化的_TYPEDEF(x,y)TYPEDEF x y;
#恩迪夫
X
是非模板参数或只有一个模板参数时,它非常有效。但是,如果
X
是具有多个参数的模板:

DOCUMENTED_TYPEDEF(Foo,Bar);
然后它会导致编译错误,因为字符串被拆分为
Foo,Bar
(并且它不会生成文档)


如何使预处理器宏贪婪?

无法更改预处理器将参数解析为宏的方式。不在括号内的逗号总是单独的宏参数

你能做的就是

DOCUMENTED_TYPEDEF((Foo<R,S>), Bar);
DOCUMENTED_TYPEDEF((Foo),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);
#定义带参数(…)(变量)__
#如果已定义(氧气处理)
#定义文档化的类型定义(x,y)类y:public STRIP\u PARENS x{};
#否则
#定义文件化的类型定义(x,y)类型定义条带x y;
#恩迪夫
记录的_TYPEDEF((Foo),Bar);

但是现在,您总是需要在文档化的\u TYPEDEF的第一个参数周围加上一对括号。

您不会喜欢这样的:

#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)
乍一看,它更具吸引力,但也可能有缺点。它更模糊。读者想知道,
PAIR
背后有语义吗?然而,
COMMA
看起来太迟钝了,没有语义,它的目的对于任何一个因为与预处理器的冲突而伤痕累累的人来说都是显而易见的

关于
PAIR
,我们可以将其隐藏起来,并以Zwol的答案中的语法结束。但是,我们需要多个
文档化的\u TYPEDEF
变体

另外,顺便说一句,让我们去掉无用的
逗号
,它不需要放在宏的右侧:

#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)
定义对(A,B)A,B #如果已定义(氧气处理) #定义文档化的_TYPEDEF_2(x2,y)类y:公共对x2{}; #否则 #定义文件化的_TYPEDEF_2(x2,y)TYPEDEF对x2 y; #恩迪夫 记录的_类型定义_2((),条) $gcc-std=c90-E-Wall-pedantic逗号宏.c #1“逗号宏.c” # 1 "" # 1 "" #1“逗号宏.c” #11“逗号宏.c” typedef条; 这看起来可能适用于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)
#定义气动逗号枪(A,…)A、#__
#如果已定义(氧气处理)
#定义文件类型定义(xv,y)y类:公共气动逗号枪xv{};
#否则
#定义文件化的_TYPEDEF(xv,y)TYPEDEF气动_逗号_枪xv y;
#恩迪夫
文件化的_TYPEDEF((),Bar)
$gcc-std=c99-E-Wall-pedantic逗号宏.c #1“逗号宏.c” # 1 "" # 1 "" #1“逗号宏.c” #9“逗号宏.c” typedef条;
那太难看了。我能指望一个不贪婪的对手吗?如果是这样,我想把
X
Y
倒过来。棘手的一点似乎是:什么是定义良好的,什么是定义实现的。我需要它在几乎所有平台的编译器上工作,而且要追溯到20世纪90年代。这是一种特殊的地狱。预处理器会将宏参数列表中未用括号括起来的逗号打断。(它计算括号内的标记,以便它们保持平衡)。方括号、大括号或尖括号不可识别;它们对逗号没有保护作用。它与贪婪无关。关于可移植性,我只使用了C90预处理器语法。我怀疑这会导致问题,因为左参数X放在声明说明符的位置。在C和C++风格声明中,声明说明符不采用可选括号。但是,声明器会这样做:
intx
int(x)是一样的<代码>(int)x
看起来像一个强制转换表达式。@Kaz您能忍受总是在可能包含模板参数的参数周围加括号,并且只支持实现C99可变宏的编译器吗?如果是这样的话,有一种破解方法可以奏效。
#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 -pedantic comma-macro.c # 1 "comma-macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "comma-macro.c" # 11 "comma-macro.c" typedef <R, S> Bar;
#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 -pedantic comma-macro.c # 1 "comma-macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "comma-macro.c" # 9 "comma-macro.c" typedef <R, S, T, L, N, E> Bar;