3

这是给C预处理器专家的:

如何声明一个enum带有一些标识符的列表,然后在 switch 语句检查列表中是否包含标识符?

我需要的示例:

typedef enum { e1, e2, e3, e4, e5, e6 } e;

e x;
switch (x) {
#if DECLARED_IN_ENUM (e1)
  case e1 : ...
#endif
  /* etc. */
}

我想过使用 Boost 序列并将其扩展为枚举中的逗号分隔列表,但是我以后如何检查该序列是否包含某个标记?

编辑:我能用 Boost 做的是:

#define e1 e1
#define e2 e2
#define e3 e3
#define e4 e4
#define e5 e5
#define e6 e6
#define E (e1)(e2)(e3)(e4)(e5)(e6)

typedef enum { BOOST_PP_SEQ_ENUM(E) } e;

e x;
switch (x) {
#if defined (e1)
  case e1 : ...
#endif
  /* etc. */
}

这不是很漂亮,我更喜欢这样的东西:

#define E (e1)(e2)(e3)(e4)(e5)(e6)

typedef enum { BOOST_PP_SEQ_ENUM(E) } e;

e x;
switch (x) {
#if BOOST_PP_SEQ_CONTAINS (e1,E)
  case e1 : ...
#endif
  /* etc. */
}

但如何BOOST_PP_SEQ_CONTAINS实施?

4

4 回答 4

4

你不能。C 预处理器不“理解”C 编程语言,它只是将它标记化。它不知道“枚举”实际上是什么意思。编译器会处理它。

如果你想在预处理器中测试某些东西,那么你必须提供预处理器宏供它使用。

编辑:抱歉,错过了您打算使用 Boost.Preprocessor。我不知道这是否可以提供必要的宏,一旦您在枚举的定义中涉及了 Boost 中的某些内容。

于 2010-09-05T16:54:40.947 回答
2

我认为BOOST_PP_SEQ_CONTAINS不能实施。这将要求您能够比较两个预处理标记序列,而这是您无法做到的。

但是,如果您稍微重新安排您的逻辑,您可以获得更接近您想要的东西。首先,我们需要几个辅助宏用于BOOST_PP_SEQ_FOR_EACH

#include <boost/preprocessor.hpp>

// General purpose macros:
#define EXPAND_ENUM_CASE_2(text1, text2) text1 ## text2
#define EXPAND_ENUM_CASE(r, data, elem) \
    case elem : EXPAND_ENUM_CASE_2(data ## _ ## CASE ## _ , elem)

我们可以像在原始问题中一样定义枚举器列表和枚举:

#define WORKDAY_ENUMERATORS (Monday)(Tuesday)(Wednesday)(Thursday)

enum Workday { BOOST_PP_SEQ_ENUM(WORKDAY_ENUMERATORS) }; 

如您所见,我将星期五排除在名单之外,因为实际上没有人在星期五工作。让我们以一个函数为例,它返回一些描述星期几的文本。

我们没有测试列表中是否包含枚举器,而是使用宏定义每个值的情况:

#define WORKDAY_CASE_Monday    { return "Mondays suck";                     }
#define WORKDAY_CASE_Tuesday   { return "Tuesdays are better than Mondays"; }
#define WORKDAY_CASE_Wednesday { return "Hooray for humpday!";              }
#define WORKDAY_CASE_Thursday  { return "Thursdays are okay";               }
#define WORKDAY_CASE_Friday    { return "No one really works on Friday";    }

然后,我们通过使用并连接带有前缀WORKDAY_ENUMERATORS的枚举数来为列表生成正确的 case 语句:WORKDAY_CASE_

const char* get_day_text(Workday d)
{    
    switch (d)
    {
        BOOST_PP_SEQ_FOR_EACH(EXPAND_ENUM_CASE, WORKDAY, WORKDAY_ENUMERATORS)
    }
    return "WTF?!  That's not a workday!";
}

如果某一天未包含在WORKDAY_ENUMERATORS列表中,则不会为其生成任何案例。

因为我们在使用预处理器时应该礼貌,所以我们取消定义我们使用的宏:

#undef WORKDAY_CASE_Monday
#undef WORKDAY_CASE_Tuesday
#undef WORKDAY_CASE_Wednesday
#undef WORKDAY_CASE_Thursday
#undef WORKDAY_CASE_Friday

我认为这有点丑陋,但这是获得几乎您所寻求的结果的一种方法。

于 2010-09-05T18:17:07.380 回答
0

只是不要使用enum. 它没有任何用处。用 声明所有常量#define,然后使用#ifdef.

于 2010-09-05T18:13:06.657 回答
0

一种方法是拥有一个涵盖所有工作日的大#define 或“.h”文件(.h 文件的优点是您不需要以反斜杠结束所有喜欢)并包含所有相关信息在宏中。然后#define 生成器宏来做某事,调用大宏(或#include 头文件),#undef 生成器宏并定义它来做其他事情,再次调用大宏,等等。在这种情况下,生成器宏会生成类似“case ENUM_foo: func_foo(); break;”的东西。然后,您可以为适当的 func_* 函数编写所有适当的代码,并且它们将被适当地调用。

于 2010-09-05T19:36:55.203 回答