C&C ++(更新后的答案)
如评论中所述,我最初的解决方案有两个问题:
- 可选参数仅在C99和语言家族的更高版本中可用。
- 枚举定义中的尾部逗号也特定于C99和更高版本。
由于我希望我的代码尽可能通用,以便在较旧的平台上工作,因此我决定再试一次。它比以前更长,但是可以在设置为C89 / C90兼容模式的编译器和预处理器上使用。所有宏都在源代码中传递了适当数量的参数,尽管有时这些宏“扩展”为空。
Visual C ++ 2013(aka版本12)发出有关缺少参数的警告,但是mcpp(声称高度符合该标准的开源预处理器)或gcc 4.8.1(带有-std = iso9899:1990 -pedantic-errors开关)都不会发出有效参数列表为空的那些宏调用的警告或错误。
在审查了相关标准(ANSI / ISO 9899-1990,6.8.3,宏替换)之后,我认为有足够的歧义,不应将其视为非标准。“在调用类似函数的宏时,参数的数量应与宏定义中的参数的数量一致……”。只要有必要的括号(在多个参数的情况下为逗号)就可以了,它似乎并不排除空的参数列表。
至于尾随逗号问题,可以通过在枚举中添加一个额外的标识符(在我的情况下为MMMM来解决,即使它不遵守公认的罗马数字排序规则,对于所有遵循3999的标识符,MMMM看起来也很合理)究竟)。
稍微干净一点的解决方案将涉及将枚举和支持的宏移到单独的头文件中,如在其他地方的注释中所隐含的那样,并在使用宏名称后立即使用undef,以避免污染名称空间。无疑也应该选择更好的宏名称,但这足以满足当前的任务。
我更新的解决方案,然后是我的原始解决方案:
#define _0(i,v,x)
#define _1(i,v,x) i
#define _2(i,v,x) i##i
#define _3(i,v,x) i##i##i
#define _4(i,v,x) i##v
#define _5(i,v,x) v
#define _6(i,v,x) v##i
#define _7(i,v,x) v##i##i
#define _8(i,v,x) v##i##i##i
#define _9(i,v,x) i##x
#define k(p,s) p##s,
#define j(p,s) k(p,s)
#define i(p) j(p,_0(I,V,X)) j(p,_1(I,V,X)) j(p,_2(I,V,X)) j(p,_3(I,V,X)) j(p,_4(I,V,X)) j(p,_5(I,V,X)) j(p,_6(I,V,X)) j(p,_7(I,V,X)) j(p,_8(I,V,X)) j(p,_9(I,V,X))
#define h(p,s) i(p##s)
#define g(p,s) h(p,s)
#define f(p) g(p,_0(X,L,C)) g(p,_1(X,L,C)) g(p,_2(X,L,C)) g(p,_3(X,L,C)) g(p,_4(X,L,C)) g(p,_5(X,L,C)) g(p,_6(X,L,C)) g(p,_7(X,L,C)) g(p,_8(X,L,C)) g(p,_9(X,L,C))
#define e(p,s) f(p##s)
#define d(p,s) e(p,s)
#define c(p) d(p,_0(C,D,M)) d(p,_1(C,D,M)) d(p,_2(C,D,M)) d(p,_3(C,D,M)) d(p,_4(C,D,M)) d(p,_5(C,D,M)) d(p,_6(C,D,M)) d(p,_7(C,D,M)) d(p,_8(C,D,M)) d(p,_9(C,D,M))
#define b(p) c(p)
#define a() b(_0(M,N,O)) b(_1(M,N,O)) b(_2(M,N,O)) b(_3(M,N,O))
enum { _ a() MMMM };
#include <stdio.h>
int main(int argc, char** argv)
{
printf("%d", MMMCMXCIX * MMMCMXCIX);
return 0;
}
原始答案(已收到前六个投票,因此,如果没有人再次投票,您不应该认为我的更新解决方案获得了投票):
本着与早期答案相同的精神,但应以仅使用定义的行为即可移植的方式进行操作(尽管不同的环境在预处理器的某些方面并不总是达成共识)。将某些参数视为可选参数,忽略其他参数,它应在不支持__VA_ARGS__
宏的预处理器(包括C ++)上工作,它使用间接宏以确保在标记粘贴之前扩展参数,最后它更短,而且我认为更易于阅读(尽管它仍然很棘手,并且可能不容易阅读,但更容易):
#define g(_,__) _, _##I, _##II, _##III, _##IV, _##V, _##VI, _##VII, _##VIII, _##IX,
#define f(_,__) g(_,)
#define e(_,__) f(_,) f(_##X,) f(_##XX,) f(_##XXX,) f(_##XL,) f(_##L,) f(_##LX,) f(_##LXX,) f(_##LXXX,) f(_##XC,)
#define d(_,__) e(_,)
#define c(_,__) d(_,) d(_##C,) d(_##CC,) d(_##CCC,) d(_##CD,) d(_##D,) d(_##DC,) d(_##DCC,) d(_##DCCC,) d(_##CM,)
#define b(_,__) c(_,)
#define a b(,) b(M,) b(MM,) b(MMM,)
enum { _ a };