19

C++03 では、クラス (または名前空間) に配置することで、厳密に型指定された列挙型をエミュレートできます。

struct MyEnum
{
  enum enumName
  {
    VALUE_1 = 1,
    VALUE_2,
  };
};

そしてそれを使用するには:

MyEnum::enumName v = MyEnum::VALUE_1;

Cで同様のことを行うことは可能ですか? はいの場合、どのように?


私はこのように試しましたが、もちろんうまくいきません:

struct A
{
  enum aa
  {
    V1 = 5
  };
};

int main()
{
  A::aa a1 = A::V1;
  enum A::aa a2 = A::V1;
  struct A::aa a3 = A::V1;

  return 0;
}
4

3 に答える 3

6

これが私の解決策です。@Ericの設計に比べていくつかの利点があります。

  • 同等性テストをサポートします(例A_VALUE_0 == value
  • C99の複合リテラルに依存しません
  • 列挙型に不適切な値を割り当てるためにキャストできます。

短所:

  • フラグが機能しない(例A_VALUE_0 | A_VALUE_1
  • switch'dできません
  • 同等性をテストするときにエラーラインがどこにあるかについてIDEを混乱させる可能性があります(例A_VALUE_0 == B_VALUE_1

ノート:

  • このタイプのポインターを逆参照しないでください。ランボルギーニよりも速くクラッシュを引き起こします

実装は次のとおりです(-Werror&でコンパイル-pedantic):

typedef struct A { char empty[1]; } *A; // we use 'empty' so that we don't get a warning that empty structs are a GNU extension
#define A_VALUE_0 ((A) 0x1)
#define A_VALUE_1 ((A) 0x2)
#define A_VALUE_2 ((A) 0x4)

typedef struct B { char empty[1]; } *B;

#define B_VALUE_0 ((B) 0x0)
#define B_VALUE_1 ((B) 0x1)
#define B_VALUE_2 ((B) 0x2)

int main()
{
    A a = A_VALUE_0;

    int equal = (a == A_VALUE_1); // works!
    int euqal = (a == B_VALUE_1) // doesn't work

    A flags = A_VALUE_0 | A_VALUE_1; // doesn't work!

    switch (a) { // doesn't work
        case A_VALUE_0:
            puts("value 0");
            break;
        case A_VALUE_1:
            puts("value 1");
            break;
        case A_VALUE_2:
            puts("value 2");
            break;
        default:
            puts("unknown value");
            break;
    } // doesn't work

    // casting works for assignment:
    A b = (A) (B_VALUE_2);

    return 0;
}
于 2012-08-10T15:24:55.410 に答える
3

C は名前空間を提供しないため、代わりにプレフィックスを使用できます。

enum MyEnum {
    MyEnumA = 1,
    MyEnumB,
    MyEnumC
};

enum OtherEnum {
    OtherEnumA = 1,
    OtherEnumB
};

次に、変数宣言を簡潔にするために、次のように列挙型の型を宣言できます。

typedef enum MyEnum MyEnum;
typedef enum OtherEnum OtherEnum;

OtherEnumB最後に、型への暗黙的な変換を許可したくない場合はMyEnum、Clang が-Wenum-conversionフラグを提供します (残念ながら GCC には同様のフラグはないと思います)。

/tmp/test.c:24:20: warning: implicit conversion from enumeration type 'enum OtherEnum' to different enumeration type 'MyEnum' (aka 'enum MyEnum') [-Wenum-conversion]
    MyEnum value = OtherEnumB;
           ~~~~~   ^~~~~~~~~~
1 warning generated.

これには、シンプルで理解しやすく、(少なくとも私の) IDE のオートコンプリートとうまく連携できるという利点があります。

于 2012-08-10T15:54:52.077 に答える
3

あなたはこれを行うことができます:

// Declare A to use for an enumeration, and declare some values for it.
typedef struct { int i; } A;
#define A0  ((A) { 0 })
#define A1  ((A) { 1 })

// Declare B to use for an enumeration, and declare some values for it.
typedef struct { int i; } B;
#define B0  ((B) { 0 })
#define B1  ((B) { 1 })


void foo(void)
{
    // Initialize A.
    A a = A0;

    // Assign to A.
    a = A1;

    // Assign a value from B to A.
    a = B0; // Gets an error.
}

これにより、ある程度の入力が可能になりますが、列挙型とその値に対して実行する他の操作によっては、面倒な場合があります。

于 2012-08-10T14:49:12.893 に答える