26

コードを短くして変更しやすくするために、次のようなものを置き換えたい

enum{ E_AAA, E_BBB, E_CCC };
static const char *strings{"AAA", "BBB", "CCC" };

INIT(AAA, BBB, CCC); のようなマクロを使用します。しかし、変数引数を使用してマクロを実行しようとすると、引数が宣言されていないため、エラーが発生します。

これを行う方法について何か考えはありますか?

4

8 に答える 8

31

これが数日前に学んだ解決策です。あなたの質問に対応する簡略版は次のとおりです。

#define ENUM_MACRO(name, v1, v2, v3, v4, v5, v6, v7)\
    enum name { v1, v2, v3, v4, v5, v6, v7};\
    const char *name##Strings[] = { #v1, #v2, #v3, #v4, #v5, #v6, #v7};

ENUM_MACRO(Week, Sun, Mon, Tue, Wed, Thu, Fri, Sat);

ただし、次のように、関数呼び出しを使用して改良版を作成できます。

#define ENUM_MACRO(name, v1, v2, v3, v4, v5, v6, v7)\
    enum name { v1, v2, v3, v4, v5, v6, v7};\
    const char *name##Strings[] = { #v1, #v2, #v3, #v4, #v5, #v6, #v7};\
    const char *name##ToString(value) { return name##Strings[value]; }

ENUM_MACRO(Week, Sun, Mon, Tue, Wed, Thu, Fri, Sat);

これは次のようになります。

  enum Week { Sun, Mon, Tue, Wed, Thu, Fri, Sat}; 
  const char *WeekStrings[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 
  const char *WeekToString(value) { return WeekStrings[value]; };

次のように、最初の要素にオフセットを使用することもできます。

#define ENUM_MACRO(name, offset, v1, v2, v3, v4, v5, v6, v7)\
    enum name { v1 =  offset, v2, v3, v4, v5, v6, v7};\
    const char *name##Strings[] = { #v1, #v2, #v3, #v4, #v5, #v6, #v7};\
    const char *name##ToString(value) { return name##Strings[value - offset ]; }

ENUM_MACRO(Week, 1, Sun, Mon, Tue, Wed, Thu, Fri, Sat);

これが役立つことを願っています。

気をつけて、ベコ

参照:

今月の質問を印刷 、クッシュ、回答 ダニー・ヴァロド

于 2011-04-03T16:43:31.007 に答える
19

ちょっとしたマクロマジックでそれを行うことができます:

#define FRUITS \
    etype(Unknown), \
    etype(Apple),   \
    etype(Orange),  \
    etype(Banana),  \
    etype(Apricot), \
    etype(Mango)

#define etype(x) F_##x

typedef enum { FRUITS } Fruit;

#undef etype
#define etype(x) #x

static const char *strFruit[] = { FRUITS };

テストプログラムは次のとおりです。

#include <iostream>
#include <exception>
#include <vector>

#define FRUITS \
    etype(Unknown), \
    etype(Apple),   \
    etype(Orange),  \
    etype(Banana),  \
    etype(Apricot), \
    etype(Mango)

#define etype(x) F_##x

typedef enum { FRUITS } Fruit;

#undef etype
#define etype(x) #x

static const char *strFruit[] = { FRUITS };

const char *enum2str (Fruit f)
{
    return strFruit[static_cast<int>(f)];
}

Fruit str2enum (const char *f)
{
    const int n = sizeof(strFruit) / sizeof(strFruit[0]);
    for (int i = 0; i < n; ++i)
    {
        if (strcmp(strFruit[i], f) == 0)
            return (Fruit) i;
    }
    return F_Unknown;
}

int main (int argc, char *argv[])
{
    std::cout << "I like " << enum2str(F_Mango) << std::endl;
    std::cout << "I do not like " << enum2str(F_Banana) << std::endl;
    std::vector<char *> v;
    v.push_back("Apple");
    v.push_back("Mango");
    v.push_back("Tomato");
    for (int i = 0; i < v.size(); ++i)
    {
        const Fruit f = str2enum(v[i]);
        if (f == F_Unknown)
            std::cout << "Is " << v[i] << " a fruit?" << std::endl;
        else
            std::cout << v[i] << " is a fruit" << std::endl;
    }
    return 0;
}

以下を出力します。

I like Mango
I do not like Banana
Apple is a fruit
Mango is a fruit
Is Tomato a fruit?
于 2011-12-01T22:35:13.010 に答える
7

Boost.Preprocessor を使用したソリューションは次のとおりです。

#include <boost/preprocessor.hpp>

#define DEFINE_ENUM_DECL_VAL(r, name, val) BOOST_PP_CAT(name, BOOST_PP_CAT(_, val))
#define DEFINE_ENUM_VAL_STR(r, name, val) BOOST_PP_STRINGIZE(val)
#define DEFINE_ENUM(name, val_seq)                                                 \
  enum name {                                                                      \
    BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(DEFINE_ENUM_DECL_VAL, name, val_seq)) \
  };                                                                               \
  static const char* BOOST_PP_CAT(name, _strings[] = ) {                           \
    BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(DEFINE_ENUM_VAL_STR, name, val_seq)) \
  };

DEFINE_ENUM(E, (AAA)(BBB)(CCC))

(AAA)(BBB)(CCC)ツリー要素 AAA、BBB、および CCC の Boost.Preprocessor シーケンスです。マクロは、そのモダリティに列挙名を追加します。

enum E { E_AAA, E_BBB, E_CCC };
static const char* E_strings[] = { "AAA", "BBB", "CCC" };
于 2011-04-03T15:08:52.047 に答える
6

これを行う 1 つの方法はX-Macrosを使用することです。これは基本的にマクロを定義する方法であり、単純なマクロでは簡単に実現できない複雑な構造を生成するために使用されます。 これは、あなたが求めていることを正確に行う例です。

于 2011-04-03T14:48:54.063 に答える
2

これを処理する 1 つの方法は、リスト マクロを定義することです。つまり、ユーザーが定義する別のマクロに展開されるものです。例えば:

#define MY_LIST MY_ENTRY(AAA) MY_ENTRY(BBB) MY_ENTRY(CCC)

を定義するにはenum:

#define MY_ENTRY(x) E_##x,
enum name
{
  MY_LIST
  NUMBER_OF_ELEMENTS    /* Needed to eat trailing comma (not needed in C99, but in C++) */
};
#undef MY_ENTRY

文字列を定義するには:

#define MY_ENTRY(x) #x,
static const char *strings[] = { MY_LIST };
#undef MY_ENTRY

X個人的には、これはインクルード ファイル マジックに依存しないため、マクロよりもはるかに扱いやすいと思います。

于 2011-04-03T15:54:59.123 に答える
1

簡単な解決策として、X-Macros のようなものをお勧めします。

他のいくつかの機能 (範囲チェック、強化された型安全性、オプションの関連データなど) を追加するより複雑なソリューションについては、提案された (ただし最終化されていない) Boost.Enum ライブラリがあります。

于 2011-04-03T17:18:39.710 に答える