2

检查以下宏:

#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

4

1 回答 1

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 中的做法。在此处查看如何使用BOOST_FUSION_ADAPT_ASSOC_STRUCT_FILLER宏。

于 2013-01-22T19:28:18.163 回答