检查以下宏:
#define INPUT (char, "microsecond", "us")(int, "millisecond", "ms")(int, "second", "s")(int, "minute", "min")(float, "hour", "h")
目标是在每个元组周围添加双括号,结果是:
((char, "microsecond", "us"))((int, "millisecond", "ms"))((int, "second", "s"))((int, "minute", "min"))((float, "hour", "h"))
现在我使用以下宏来完成这项工作:
#define ADD_PAREN_1(A, B, C) ((A, B, C)) ADD_PAREN_2
#define ADD_PAREN_2(A, B, D) ((A, B, C)) ADD_PAREN_1
#define ADD_PAREN_1_END
#define ADD_PAREN_2_END
#define OUTPUT0 ADD_PAREN_1 INPUT
#define OUTPUT1 BOOST_PP_CAT( OUTPUT0, _END )
结果如下:
OUTPUT0很好:
((char, "microsecond", "us")) ((int, "millisecond", C)) ((int, "second", "s")) ((int, "minute", C)) ((float, "hour", "h")) ADD_PAREN_2
但是当调用BOOST_PP_CAT时,OUTPUT1的结果是:
float
我不明白这种行为。任何提示?
注意我使用Visual Studio 2010
答案 0 :(得分:2)
预处理器通过扫描和扩展来工作。因此,当它扩展您的OUTPUT0
宏时,它会给出:
ADD_PAREN_1 INPUT
^
然后它扫描下一个标记以查看它是否是括号,如果是,它将调用ADD_PAREN_1
作为函数宏。但是,它只会看到INPUT,因此它不会调用ADD_PAREN_1
。接下来,它会扫描并展开下一个标记:
ADD_PAREN_1 INPUT
^
这将导致:
ADD_PAREN_1 (char, "microsecond", "us")(int, "millisecond", "ms")(int, "second", "s")(int, "minute", "min")(float, "hour", "h")
^
接下来,当您尝试使用OUTPUT1
时,它将扩展为:
BOOST_PP_CAT( OUTPUT0, _END )
哪个BOOST_PP_CAT
会扩展OUTPUT0
然后连接令牌,所以你最终会得到这个:
ADD_PAREN_1 (char, "microsecond", "us")(int, "millisecond", "ms")(int, "second", "s")(int, "minute", "min")(float, "hour", "h") ## _END
正如您所看到的那样,您正在使用_END
括号括号,这是不允许的,并导致编译器错误。在Visual Studio中,您可能会看到不同的结果,因为它们的预处理器以神秘的方式工作。
最终,要使其工作,您只需在OUTPUT0
宏中应用额外扫描,如下所示:
#define X(x) x
#define OUTPUT0 X(ADD_PAREN_1 INPUT)
哪些适用于C预处理器,我不知道它是否能在Visual Studio中完全正常工作(我现在无法访问它来检查),但我确实知道这有效:
#define ADD_PAREN(x) BOOST_PP_CAT(ADD_PAREN_1 x, _END)
#define ADD_PAREN_1(A, B, C) ((A, B, C)) ADD_PAREN_2
#define ADD_PAREN_2(A, B, D) ((A, B, C)) ADD_PAREN_1
#define ADD_PAREN_1_END
#define ADD_PAREN_2_END
#define OUTPUT1 ADD_PAREN(INPUT)
这类似于他们在提升方面的表现。了解如何使用BOOST_FUSION_ADAPT_ASSOC_STRUCT_FILLER宏here。