(方法)列挙型のアイテムを数えることはできますか?


98

このような疑問が浮かんだのは、

enum Folders {FA, FB, FC};

そして、各フォルダのコンテナの配列を作成したいと思いました:

ContainerClass*m_containers[3];
....
m_containers[FA] = ...; // etc.

(使い方はそれを使用するためにはるかにエレガントだマッピングされますstd::map<Folders, ContainerClass*> m_containers;

しかし、元の質問に戻ります。配列のサイズをハードコード化したくない場合、フォルダー内のアイテム数を把握する方法はありますか?(たとえばFC、リストの最後のアイテムであることに依存せずにContainerClass*m_containers[FC+1]、私が間違っていないようなものを許可します。)


この投稿はあなたの質問に答えるかもしれません:stackoverflow.com/questions/1390703/enumerate-over-an-enum-in-c
StackedCrooked 2010年

1
質問は少々指定不足です。C ++標準に従って、変数のint(FA) | int(FB) | int (FC)正当な値でもありFoldersます。変数が有効なインデックスになるm_containersようにサイズを変更する場合Folders[FC+1]十分な大きさにはなりません。
MSalters '25 / 07/25


回答:


123

これを行うには良い方法はありません。通常、列挙型に追加のアイテムが表示されます。

enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};

だからあなたはできる:

int fuz[FOOBAR_NR_ITEMS];

それでもあまり良くありません。

しかしもちろん、列挙型のアイテムの数だけでは安全ではないことに気づきます。

enum foobar {foo, bar = 5, baz, quz = 20};

項目の数は4ですが、列挙値の整数値は、配列のインデックスの範囲から大きく外れます。配列のインデックス付けに列挙値を使用することは安全ではないため、他のオプションを検討する必要があります。

編集:要求に応じて、特別なエントリをさらに目立たせました。


27
LAST、ALWAYS_AT_END、またはそれほどわかりにくいものを呼び出します。突き出してください。マーカーを終了した後に後続のメンテナが誤って新しいエントリを追加しないように。
マーティンヨーク

3
良くも悪くも、これは私たちの組織で採用するアプローチです。通常、FINAL_foobar_ENTRYなど、FINAL_enumname_ENTRYと呼びます。また、列挙型宣言の直後に定義された別の静的const FOOBAR_COUNT変数を使用する人々を見たこともあります。これは、少しエラーが発生しやすいアプローチです。
ダリル

1
少なくとも、「enum foo {a = 10、LAST}」が奇妙になることはかなり簡単にわかります。そして、私は「int型のARR [LAST]が」このケースでは11の項目となり、ない2ので、ほとんどのコードは動作します(ただし、無効なインデックス値にしている消耗メモリ)と思った
コードAbominator

32

C ++では、さまざまなタイプセーフな列挙型テクニックが利用可能であり、それらのいくつか(提案されているが決して送信されないBoost.Enumなど)には、列挙型のサイズを取得するためのサポートが含まれています。

CおよびC ++で機能する最も簡単な方法は、列挙型ごとに... MAX値を宣言する規則を採用することです。

enum Folders { FA, FB, FC, Folders_MAX = FC };
ContainerClass *m_containers[Folders_MAX + 1];
....
m_containers[FA] = ...; // etc.

編集{ FA, FB, FC, Folders_MAX = FC}対対{FA, FB, FC, Folders_MAX]:私はいくつかの理由で... MAX値を列挙型の最後の正当な値に設定することを好みます:

  1. 定数の名前は技術的にはより正確です(Folders_MAX可能な最大の列挙値を与えるため)。
  2. 個人的には、Folders_MAX = FC他のエントリから少し目立つように感じます(Martin Yorkが言及した問題である最大値を更新せずに誤って列挙値を追加するのが少し難しくなります)。
  3. GCCには、次のようなコードに対して「スイッチに含まれていない列挙値」などの役立つ警告が含まれています。Folders_MAX == FC + 1にすると、スイッチに含めてはならない一連の... MAX列挙値が作成されるため、これらの警告は発生しません。
スイッチ(フォルダ) 
{
  ケースFA:...;
  ケースFB:...;
  //おっと、FCを忘れました!
}

3
なぜしないのですenum Folders { FA, FB, FC, Folders_MAX }; ContainerClass *m_containers[Folders_MAX];か?
Bill

1
私は最後が数字であることを明確にしたいと思います、そしておかげでそれらはすべて同じ名前を持っています:struct SomeEnum { enum type {FA, FB, FC, NB__};};
Luc Hermitte

2
実際、私はこれらの「役立つ」警告はお尻の痛みだと感じています。私は開発中に常に-Wall -pedanticなどを設定する適切な警告が好きですが、これらの警告は愚かです。&& ||のカッコを提案するように、少し悪いだけです。と&^ | 演算子の優先順位。私は、私は...地獄はCやC ++に何が起こっているのか、Javaはベビーシッター言語だと思ったわけ
ウィッヒ

2
Folders_max = FCの欠点は、列挙型に何かを追加するたびに変更する必要があることです。
エティエンヌ2014年

2
列挙型フォルダ{FA、FB、FC、Folders_MIN = FA、Folders_MAX = FC}; それが反復に役立つことを強調するだけですか?
gjpc 2015年

7

STL方式の特性についてはどうですか?例えば:

enum Foo
{
    Bar,
    Baz
};

書く

std::numeric_limits<enum Foo>::max()

特殊化(c ++ 11を使用している場合はおそらくconstexpr)。次に、テストコードで静的アサーションを提供して、std :: numeric_limits :: max()= last_itemである制約を維持します。


2
残念ながら、これはこの回答に従って機能しません。
rr-

3
std::numeric_limits<enum Foo>::max()常にゼロを返します...(リンクされた回答の質問を参照してください)通常の列挙型(enum Foo { ... })、型ヒント列挙型(enum class Foo : uint8_t { ... })でgcc 5.2.0 @ LinuxおよびMinGW 4.9.3 @ Windowsでテストされています。
rr-

1
(...およびの場合、std::numeric_limits<std::underlying_type<Foo>::type>::max()32ビット整数の0xFFFFFFFFを返すため、このコンテキストでは役に立ちません。)
rr-

1
奇妙なのは、私が説明したことを実行する作業コードがあるからです。namespace gx { enum struct DnaNucleobase : char { A, C, G, T }; } そして、:namespace std { template<> struct numeric_limits<enum ::gx::DnaNucleobase> { typedef enum ::gx::DnaNucleobase value_type; static constexpr value_type max() { return value_type::T; } (...) そして、std::cout << std::numeric_limits<::gx::DnaNucleobase>::max() << std::endl;プリント結果を期待。gcc 5.2.1および4.8 / 4.9フレーバーでテスト。
Wojciech Migda

2
-1; 回答を変更した場合はpingを送信して、反対票を取り消すことができます。この答えは従うべき悪い慣習です。これはの概念の誤用ですnumeric_limits<T>::max()。関数が合理的に返すことができる唯一のものは、最も高い列挙値です。それはを返します2が、OP(この特定の場合)はを返す必要があり3ます。enum(FB = 2057)にデフォルト以外の値を設定すると、すべてのベットがオフに+ 1なり、off-by-oneエラーを回避することさえできなくなります。numeric_limits<T>::number_of_elements_of_the_set()(または短い名前)があった場合、あいまいさなく使用できます。
Merlyn Morgan-Graham 2017

3

列挙型の最後に、Folders_MAXなどのエントリを追加し、配列を初期化するときにこの値を使用します。

ContainerClass* m_containers[Folders_MAX];

2

列挙型を関数の引数として使用したい。これは、「オプション」の固定リストを提供する簡単な方法です。ここでトップ投票の回答の問題は、それを使用して、クライアントが「無効なオプション」を指定できることです。スピンオフとして、基本的に同じことを行うことをお勧めしますが、列挙型の外で定数の整数を使用して、それらの数を定義します。

enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;

これは快適ではありませんが、定数を更新せずに列挙型を変更しない場合は、クリーンなソリューションです。


1

C ++で列挙型の値の数を実際に取得する方法はありません。配列の作成が大きすぎたり小さすぎたりする状況に遭遇する可能性がある値を定義する場合、列挙の値を定義しない限り、前述の解決策のいずれかが機能します

enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }

これについての例では、5つの項目の配列が必要な場合、結果は3つの項目の配列を作成します

enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }

この例の例では、5つの項目の配列が必要な場合、結果は301項目の配列を作成します

一般的なケースでこの問題を解決する最良の方法は、列挙を反復処理することですが、私が知る限り、それは標準にはまだありません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.