C++ で列挙型を記述するときのパターンにたどり着きました。次のようになります。
class Player
{
public:
class State
{
public:
typedef enum
{
Stopped,
Playing,
Paused
}PossibleValues;
static const int Count() {return Paused+1;};
static const PossibleValues Default() {return Stopped;};
};
//...
}
これにより、外部の名前空間の汚染など、列挙型に関する通常の問題のいくつかが解決されます。ただし、まだ気に入らない点があります。Count() は手動で行われます。私が知っている方法は 2 つしかありません。これは Last+1 から計算されます。またはハードコードされたプレーンな書き込み。
質問: プリプロセッサ マクロを使用するなど、カウントを自動的に取得して Count() メソッドの後に配置する方法はありますか? 注意: enum 内に Count という最後の偽の要素を入れて、それを汚染したくありません!
前もって感謝します!
更新 1:
より高度な列挙型の提案について、標準 C++11 での N4428 列挙型リフレクションの実装 (部分的)に関する興味深い議論があります。
更新 2:
興味深いドキュメントN4451- MetaEnums および MetaEnumClasses に関するセクション 3.16、3.17、A.7、A.8 の静的リフレクション (rev. 3) 。
更新 3:
https://bytes.com/topic/c/answers/127908-numeric_limits-specialization#post444962を見た後、列挙型クラスを使用して別の興味深いパターンにたどり着きました。enum クラスの列挙子リストが連続して integerである場合、その最大値と最小値を定義することで、値がそれに属するかどうかを確認できます。
Count()
でメソッドを使用する目的がPlayer::State
値が列挙に含まれているかどうかを確認することであった場合、その目的は numeric_limits アプローチでも達成されており、列挙子リストがゼロ値の項目で始まる必要がないため、さらに優れています。 !
enum class Drink
{
Water,
Beer,
Wine,
Juice,
};
#pragma push_macro("min")
#undef min
#pragma push_macro("max")
#undef max
namespace std
{
template <> class numeric_limits < Drink >
{
public:
static const/*expr*/ bool is_specialized = true;
static const/*expr*/ Drink min() /*noexcept*/ { return Drink::Water; }
static const/*expr*/ Drink max() /*noexcept*/ { return Drink::Juice; }
static const/*expr*/ Drink lowest() /*noexcept*/ { return Drink::Water; }
static const/*expr*/ Drink default() /*noexcept*/ { return Drink::Beer; }
};
}
#pragma pop_macro("min")
#pragma pop_macro("max")
使用例:
アプリケーションからの変数:
Drink m_drink;
コンストラクターで次のように初期化されます。
m_drink = numeric_limits<Drink>::default();
フォームの初期化時に、次のことができます。
pComboDrink->SetCurSel(static_cast<int>(theApp.m_drink));
その上で、ユーザーが行った変更にインターフェイスを適応させるために、スコープ付きの列挙型クラス値を使用して切り替えを行うことができます。
switch (static_cast<Drink>(pComboDrink->GetCurSel()))
{
case Drink::Water:
case Drink::Juice:
pAlcohoolDegreesControl->Hide();
break;
case Drink::Beer:
case Drink::Wine:
pAlcohoolDegreesControl->Show();
break;
default:
break;
}
そして、ダイアログの確認手順 ( OnOK
) で、それぞれのアプリ変数に保存する前に、値が境界外であるかどうかを確認できます。
int ix= pComboDrink->GetCurSel();
if (ix == -1)
return FALSE;
#pragma push_macro("min")
#undef min
#pragma push_macro("max")
#undef max
if (ix < static_cast<int> (std::numeric_limits<Drink>::min()) || ix > static_cast<int> (std::numeric_limits<Drink>::max()) )
return FALSE;
#pragma pop_macro("min")
#pragma pop_macro("max")
theApp.m_drink= static_cast<Drink>(ix);
ノート:
- キーワード
constexpr
(私はコメントしましたが、その/*expr*/
ままにしておきますconst
) とnoexcept
は、私が使用しているコンパイラ (Visual C++ 2013) が現在のバージョンでまだサポートしていないため、コメントされています。 - おそらく、最小マクロと最大マクロを一時的に未定義にするロジックは必要ありません。
default()
が「数値制限」の範囲に収まらないことはわかっています。しかし、それを置くのに便利な場所に思えました。default
文脈によってはキーワードであるという単語と一致します。