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シーケンスを使用して、列挙型のコンマ区切りリストに展開することを考えましたが、シーケンスに特定のトークンが含まれているかどうかを後で確認するにはどうすればよいですか?

編集:私がブーストでできたことは:

#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実装できないと思います。前処理トークンの2つのシーケンスを比較できる必要がありますが、これはできません。

ただし、ロジックを少し再配置すると、必要なものに近づけることができます。まず、以下で使用するためのヘルパーマクロがいくつか必要です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

1つのアプローチは、すべての平日をカバーし(.hファイルには、すべてのいいねをバックスラッシュで終了する必要がないという利点があります)、それらに関連するすべての情報を含む、大きな#defineまたは「.h」ファイルを用意することです。マクロで。次に、ジェネレーターマクロを定義して何かを実行し、ビッグマクロを呼び出し(またはヘッダーを含めます)、ジェネレーターマクロを定義解除して別のことを実行するように定義し、ビッグマクロを再度呼び出します。このシナリオでは、ジェネレータマクロは、「case ENUM_foo:func_foo();break;」のようなものを生成します。次に、適切なfunc_ *関数に適切なすべてのコードを記述して、それらを適切に呼び出すことができます。

于 2010-09-05T19:36:55.203 に答える