web-dev-qa-db-ja.com

配列インデックスとして列挙型を使用する

私はこの列挙型を持っています:

enum ButtonState {
    BUTTON_NORMAL = 0,
    BUTTON_PRESSED = 1,
    BUTTON_CLICKED = 2
};

const u8 NUM_BUTTON_STATES = 3;

Buttonクラスには、ButtonState state;およびButtonColors colors[NUM_BUTTON_STATES];というメンバー変数があります。ボタンを描画するときは、colors[state]を使用して、ボタンの状態に関係なく色を取得します。

私の質問:

  1. これは良いプログラミングスタイルですか?それを行うより良い方法はありますか? (私は通常、switchステートメントで列挙型のみを使用します...配列インデックスとして列挙型を使用するのは適切ではありません。)
  2. haveを使用して、列挙型の値を指定しますか?デフォルトでは0から始まり1ずつ増加するようですが、すべてのコンパイラでそのように動作することが保証されていますか?
56
Jeremy Ruten

これは良いプログラミングスタイルですか?

私はそう思う。私は非常に頻繁に同じことをします。

もっと良い方法はありますか?

class Button
{
public:
    // Used for array indexes!  Don't change the numbers!
  enum State {
    NORMAL = 0,
    PRESSED,
    CLICKED,
    NUMBER_OF_BUTTON_STATES
  };
};

欠点は、NUMBER_OF_BUTTON_STATESが有効なButton :: State値になったことです。これらの値をintsとして渡す場合、大きな問題ではありません。しかし、実際にButton :: Stateを期待している場合は問題があります。

列挙型を配列インデックスとして使用するのは適切ではありません。

大丈夫だよ。ただ[〜#〜] document [〜#〜] itなので、次の人は何が起こっているのか知っています! (それがコメントの目的です。)

enumの値を指定する必要がありますか?

'='割り当てがない場合、enumゼロから開始して上向きに増分することになっています。

Enumエントリに「=」が割り当てられた値がある場合、後続の非「=」enumエントリはそこからカウントを続けます。

出典:The Annotated C++ Reference Manual、pg 113

そうは言っても、コードをより明確にするためだけに初期値を指定するのが好きです。

47
Mr.Ree

ええ、うまくいきます。とはいえ、いずれにしても、reallyアイテムの量の値を定義する別のエントリを列挙に追加する必要があります。

enum ButtonState {
    BUTTON_NORMAL,
    BUTTON_PRESSED,
    BUTTON_CLICKED,
    STATE_COUNT
};

次に、配列を次のように定義できます

Color colors[STATE_COUNT];

そうでなければ、状態の量を配列のサイズと同期させておくのは面倒です。列挙は、初期化されていない場合は常にゼロで始まり、初期化されていない場合、追加の各エントリには前のエントリの1つ上の値が割り当てられます。もちろん、必要に応じて明示的にゼロを設定しても問題はありません。追加のコードを気にしない場合は、次のような関数を使用して生の配列へのアクセスをラップします

Color & operator[](ButtonState state) {
    return array[state];
}

または、リクエストを転送する同等のgetColor関数。これは、何らかの整数で配列に直接インデックスを付けることを禁止しますが、インデックスを間違えると、ほぼ確実に失敗します。

列挙型を使用しても問題ありません。ただし、すべてのアイテムに値を指定する必要はありません。最初の値を指定するだけで十分です。私は1を開始値として使用したコンパイラを使用しているため、列挙型が0で始まるとは想定していません(PC用ではなく、マイクロコントローラ用のコンパイラには奇妙な動作があります)。また、constを取り除くこともできます。

enum ButtonState {
    BUTTON_NORMAL = 0,
    BUTTON_PRESSED,
    BUTTON_CLICKED,
    NUM_BUTTON_STATES
};
15
Stefan

質問1:良いプログラミングスタイルだと思います。いつも使っています。質問2:私の知る限り、そのように動作することが保証されているため、値を指定する必要はありません。

そして、NUM_BUTTON_STATESも列挙に入れます。

3
Nathan Stoddard

スタイルに関しては、それで十分です。

DelphiなどのPascalベースの言語では、配列の境界を列挙型として指定できるため、その特定の型の項目のみをインデックスとして使用できます。

3
Roddy

配列へのインデックス付けに列挙型を使用するのは完全に正常です。

各列挙値を指定する必要はありません。それらは自動的に1ずつ増加します。コンパイラーに値を選択させると、ミスタイプやバグの作成の可能性が減りますが、デバッグに役立つ可能性のある値が表示されなくなります。

1
Mark Ransom

大丈夫ですが、誰かが別のButtonStateを追加した場合に問題が発生するように、配列の境界チェックを行いたいと思います。

また、colors配列の要素は不変であるため、配列に別のコレクションを使用して、その不変性を強制できるようにすることを検討してください。たぶんDictionary<ButtonState,ButtonColor>

1
WOPR