cプリプロセッサマクロ:トークンが宣言されたかどうかを確認します
-
01-10-2019 - |
質問
これはのためです c プリプロセッサの専門家:
どうすれば宣言できますか enum
いくつかの識別子のリストを使用して、後でスイッチステートメント中に識別子がリストに含まれているかどうかを確認しますか?
必要なものの例:
typedef enum { e1, e2, e3, e4, e5, e6 } e;
e x;
switch (x) {
#if DECLARED_IN_ENUM (e1)
case e1 : ...
#endif
/* etc. */
}
ブーストシーケンスを使用して、列挙のコンマ分離リストに拡張することを考えましたが、シーケンスに特定のトークンが含まれているかどうかを後で確認するにはどうすればよいですか?
編集: :私がブーストでできることは次のとおりです。
#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
実装されますか?
解決
私は考えていません 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
列挙者を連結します 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!";
}
1日が含まれていない場合 WORKDAY_ENUMERATORS
リスト、そのためにケースは生成されません。
プリプロセッサを使用するときは礼儀正しくなければならないので、使用したマクロを定義していません。
#undef WORKDAY_CASE_Monday
#undef WORKDAY_CASE_Tuesday
#undef WORKDAY_CASE_Wednesday
#undef WORKDAY_CASE_Thursday
#undef WORKDAY_CASE_Friday
これは醜いと思いますが、それはあなたが求めているほぼ結果を得るための1つの方法です。
他のヒント
できません。 Cプリプロセッサは、Cプログラミング言語を「理解」せず、単にトークン化します。 「Enum」が実際に何を意味するのかはわかりません。コンパイラはそれを処理します。
プリプロセッサで何かをテストしたい場合は、使用するためのプリプロセッサマクロを提供する必要があります。
編集:申し訳ありませんが、Boost.Preprocessorを使用するつもりだったことを逃しました。必要なマクロを提供できるかどうかはわかりません。
使用しないでください enum
. 。有用な目的はありません。すべての定数を宣言します #define
, 、使用してください #ifdef
.
1つのアプローチは、すべての平日をカバーする素晴らしい大きな#defineまたは ".h"ファイルを持っていることです(.hファイルには、バックスラッシュですべての好きなものを終わらせる必要がないという利点があり、それらのすべての関連情報が含まれています。マクロで。次に、#ジェネレーターマクロを定義して何かを行い、大きなマクロを呼び出し(または#include the header)、ジェネレーターマクロを作成して他のことを行うように定義し、再び大きなマクロを呼び出します。ジェネレーターマクロは、「case enum_foo:func_foo(); break;」のようなものを生成します。その後、適切なFUNC_*関数のすべての適切なコードを記述することができ、それらは必要に応じて呼び出されます。