C++11 では、改良さenum
れたenum struct
. しかし、これは確かに - あなたがそれに慣れるまで - 下位の古いものの最も驚くべき落とし穴に苦しんでいますenum
: 型の変数の値はenum struct E
、列挙されたもののいずれかである必要はありませんが、E
の基になる整数型:
enum struct X { one = 1};
X x = X(); // Fine! The value of x is int(0)
x = X(2); // Cool! The value of x is int(2)
enum
またはenum struct
typeのオブジェクトを使用するあらゆる場所で、それが「 のE
1 つではない」ケースをキャッチする必要がありますE
。
インスタンス化クラスのオブジェクトが「列挙された」もの以外の値を想定できないというプロパティを使用して、(必ずしもドロップイン代替であるとは限らない)代わりに使用できるジェネリック型を定義するにはどうすればよいでしょうか?enum struct
つまり、オブジェクトが区別されない値を想定するのではなく、スローする場合に満足することはできません(つまり、「s の1 つにならない」場合をキャッチしますE
)。
そして、これらの値が一連の整数型テンプレート パラメーターによって "列挙" され、X::one
.
それが避けられない場合は、「列挙された」値が型から列挙インデックスによって静的に取得可能な定数になる限り、問題ありません。(そうすれば、クライアント コードで、意味のあるシンボルをインデックスまたはインデックス付きの値に関連付けて、そのような便利なマッピングをカプセル化することが簡単になります。たとえば、struct
ネストされた匿名でenum
!)
私が知らないこの質問に対する定評のある解決策は既にありますか?
コメンテーターのリクエストにより続きます (Ali)
疑似コードを投稿できますか?どのように使用したいかを示す必要があります。
ここに、望ましい使用法のいくつかの兆候があります(私は思います):
/* 1 */
/* These 2 structs could just be tag-types X{}, Y{}
serving to distinguish value-safe-enums that
would otherwise be the same. But you could
also get more mileage out them, as shown...
*/
struct turn;
struct hand;
using vs_turn = val_safe_enum<turn,int,1,2>;
using vs_hand = val_safe_enum<hand,int,1,2>;
struct turn
{
// Want an anonymous scoped enum; only rvalue
enum {
right = vs_turn::which<0>(), // = 1
left = vs_turn::which<1>() // = 2
};
};
struct hand
{
enum {
right = vs_hand::which<0>(), //= 1
left = vs_hand::which<1>() // = 2
};
};
/* End 1 */
/* 2 */
char const * foo(vs_turn const & t) {
// Only 2 possibilities!
return int(t) == turn::right ? "right turn" : "left turn";
}
char const * foo(vs_hand const & h) {
return int(h) == hand::right ? "right hand" : "left hand";
}
/* End 2 */
vs_turn t1(0); // 3.a OK
vs_turn t2(turn::right); // 3b. OK
vs_hand h1(hand::left); // 3c. OK
vs_hand h2(1); // 3d. OK
t1 == vs_turn(turn::right); // 4. OK
t1 < t2; // 5. OK
t1 = t2; // 6. OK
int(t1) == turn::right; // 7. OK. Explicit conversion to underlying type.
/* 8 */
switch(int(t1)) {
case turn::right:
/* Something */ break;
case turn::left:
/* Something */;
// No default necessary!
}
/* End 8 */
vs_turn t3(3); // 9. Throw! Value out of range
vs_turn t4; // 10. Error. No default construction.
t1 == turn::right; // 11a. Error. No Conversion
t1 <= h1; // 11b. Error. No conversion.
t1 = turn::right; // 11c. Error. No conversion
t1 = h1; // 11d. Error. No conversion.
foo(turn::right); // 11e. Error. No conversion