他の場所で指摘されているように、問題は名前空間とは関係ありませんが|、intを作成するために使用し、その値を.を期待する関数に渡そうとすることと関係がありenumます。問題を「捨てる」場合でも、型であると主張する変数に不一致な値が含まれることになりますFeeling::e。
多くの場合、enumメンバーが自然な順序で連続した値を取得できるようにする方が便利です。これにより、メンバーをインデックス値として簡単に使用できるようになり、コンパイラーは、メンバーを計算されたgotoに使用するswitchステートメントを最適化するための機能を備えていることがよくあります。enumただし、メンバーのコレクションをセットのように渡す必要がある場合がよくあります。
enumこれは、をフラグ値に変換するために使用するヘルパーの簡略化されたバージョンです。enumこれは、すでに順次定義されているが、それらのコレクションをセットとして表現したいコードに特に役立ちます。まず、それがどのように使用されるかの例(そして、ビット演算の結果をenum型にキャストするソリューションが、同様の結果を達成するために奇妙なことをしなければならないことに注意してください)。
namespace Feeling {
enum e { Happy, Sad, Blue, Angry, Mad, MAX_e };
std::string estr[] = { "Happy", "Sad", "Blue", "Angry", "Mad" };
}
void HowDoYouFeel (const Flags<Feeling::e> &feelings)
{
for (int i = 0; i < Feeling::Max_e; ++i) {
if (feelings.has(i)) std::cout << Feeling::estr[i] << std::endl;
}
if (feelings.has(Feeling::Angry)) {
std::cout << "The Hulk is in the house." << std::endl;
}
}
HowDoYouFeel(Feeling::Happy | Feeling::Blue | Feeling::Mad);
これは、演算子のオーバーロード、テンプレート、およびヘルパーテンプレートを使用して実現されます。コードがインライン化されているため、最適化が有効になっている実際の実行時オーバーヘッドは低く、enum定数のシフト演算はコンパイル時に計算されます。
template <typename E>
class Flags
{
unsigned long long m_opts;
public:
Flags () : m_opts(0) {}
Flags (E e) : m_opts(1ULL << e) {}
Flags (const FlagsTmp<E> &ot) : m_opts(ot.m_opts) {}
bool has (unsigned i) const { return m_opts & (1ULL << i); }
bool has (E e) const { return m_opts & (1ULL << e); }
};
Flagsテンプレートは、型をテンプレートパラメータとして受け取り、enum初期化するためのいくつかの簡単な方法を提供します。このhasメソッドはenum、が設定されたフラグの1つであるかどうかを確認するために使用されます。
template <typename E>
class FlagsTmp
{
friend class Flags<E>;
mutable unsigned long long m_opts;
public:
FlagsTmp (E e) : m_opts(1ULL << e) {}
const FlagsTmp & operator | (E e) const {
m_opts |= (1ULL << e);
return *this;
}
};
FlagsTmpすべてのフラグを収集するための仲介として使用されます。|これにより、フラグを操作と一緒に1つのFlagsTmpインスタンスに結合できます。
template <typename E>
FlagsTmp<E> operator | (E e, E f) { return FlagsTmp<E>(e) | f; }
この演算子は、|演算子をオーバーロードして、2つのenumフラグまたは-dを一緒に。に変換しFlagsTmpます。
bitset使用するソリューションを適応させたり、テスト方法や演算子を追加したりするなど、ニーズに合わせてこれを拡張する方法はいくつかあります。