0

名前空間に列挙型を配置すると、2つの列挙型が1つの同じ名前のアイテムを共有する場合のコンパイルエラーを回避できることを学びました。

namespace Feeling
{
    enum e
    {
        Happy = 1,
        Sad = 2,
        Blue = 4,
        Angry = 8,
        Mad = 16
    };
}

したがって、次のように宣言されている関数に渡すことができます

void HowDoYouFeel(Feeling::e feeling);

しかし、次のようにORしようとすると:

HowDoYouFeel(Feeling::Happy | Feeling::Blue);

エラーが発生します。これを処理するための最良の方法は何ですか?

4

5 に答える 5

5

問題を詳しく説明するときは、次のことを指定する必要があります。

  • 問題を示す最小限のコードサンプル。
  • 予想される動作。と
  • 実際の動作。

この場合、発生するエラーを見逃しています。たとえば、次のコードです。

namespace Feeling {
    enum e { Happy = 1, Sad = 2, Blue = 4, Angry = 8, Mad = 16 };
}

int main() {
    Feeling::e ff1;
    ff1 = Feeling::Happy | Feeling::Sad;
    // ff1 = (Feeling::e)(Feeling::Happy | Feeling::Sad);
    return 0;
}

エラーが発生します:

error: invalid conversion from ‘int’ to ‘Feeling::e’

|演算子の結果が。であるためintです。

ただし、最初の割り当てをコメントアウトし、2番目の割り当て(明示的なキャストを含む)を使用すると、コンパイルは問題ありません。

于 2012-06-05T06:12:00.540 に答える
1

質問は、少し主観的な「最高の方法」を求めています。私はこれらの場合のために、それが直交エンコーディングを持っているe operator|(e left, e right) { return e(int(left)|int(right)); }ことを明確にするために書きます。Feeling::e

于 2012-06-05T07:30:31.807 に答える
0

列挙型は整数に他なりません。列挙型の代わりに整数(または符号なし整数)を入力として使用するように関数を変更できます。

void HowDoYouFeel (int feelingMask);

次に、次のような呼び出しではエラーは発生しません:-

HowDoYouFeel(Feeling::e::Happy | Feeling::e::Blue)
于 2012-06-05T06:15:12.077 に答える
0

他の場所で指摘されているように、問題は名前空間とは関係ありませんが|、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使用するソリューションを適応させたり、テスト方法や演算子を追加したりするなど、ニーズに合わせてこれを拡張する方法はいくつかあります。

于 2012-06-05T07:11:39.067 に答える
0

あなたの質問への簡単な答え:

  1. 名前空間とは何の関係もありません。
  2. あなたの呼び出しには暗黙の変換があります:Feeling :: Happy | Feeling :: Blueは、列挙型から整数型への変換を引き起こします。HowDoYouFeel(Feeling :: Happy | Feeling :: Blue)は、コンパイラで許可されていない整数から列挙型への変換を引き起こすため、エラーが発生します。
于 2012-06-05T07:46:46.503 に答える