web-dev-qa-db-ja.com

スコープ付き列挙型で| =演算子をオーバーロードする方法は?

厳密に型指定された(スコープの)enum|=演算子をどのようにオーバーロードできますか(C++ 11では、GCC )?

強く型付けされた列挙型のビットをテスト、設定、クリアしたい。なぜ強く型付けされたのですか?私の本はそれが良い習慣だと言っているので。しかし、これは私がどこにでもstatic_cast<int>しなければならないことを意味します。これを防ぐために、|演算子と&演算子をオーバーロードしますが、|=演算子on enumをオーバーロードする方法がわかりません。クラスの場合は、単純に クラスの演算子定義 を指定しますが、列挙型の場合は構文的に機能しないようです。

これは私がこれまでに持っているものです:

enum class NumericType
{
    None                    = 0,

    PadWithZero             = 0x01,
    NegativeSign            = 0x02,
    PositiveSign            = 0x04,
    SpacePrefix             = 0x08
};

inline NumericType operator |(NumericType a, NumericType b)
{
    return static_cast<NumericType>(static_cast<int>(a) | static_cast<int>(b));
}

inline NumericType operator &(NumericType a, NumericType b)
{
    return static_cast<NumericType>(static_cast<int>(a) & static_cast<int>(b));
}

私がこれを行う理由:これは、厳密に型指定されたC#で機能する方法です。列挙型には、基礎となる型のフィールドを持つ構造体と、それに定義された定数の束があります。ただし、列挙型の隠しフィールドに収まる任意の整数値を持つことができます。

また、C++列挙型もまったく同じように機能するようです。どちらの言語でも、キャストはenumからintに、またはその逆に移動する必要があります。ただし、C#ではビット演算子はデフォルトでオーバーロードされ、C++ではオーバーロードされません。

inline NumericType& operator |=(NumericType& a, NumericType b)
{
    return a= a |b;
}

これは機能しますか? コンパイルして実行:(イデオネ)

#include <iostream>
using namespace std;

enum class NumericType
{
    None                    = 0,

    PadWithZero             = 0x01,
    NegativeSign            = 0x02,
    PositiveSign            = 0x04,
    SpacePrefix             = 0x08
};

inline NumericType operator |(NumericType a, NumericType b)
{
    return static_cast<NumericType>(static_cast<int>(a) | static_cast<int>(b));
}

inline NumericType operator &(NumericType a, NumericType b)
{
    return static_cast<NumericType>(static_cast<int>(a) & static_cast<int>(b));
}

inline NumericType& operator |=(NumericType& a, NumericType b)
{
    return a= a |b;
}

int main() {
    // your code goes here
    NumericType a=NumericType::PadWithZero;
    a|=NumericType::NegativeSign;
    cout << static_cast<int>(a) ;
    return 0;
}

印刷3。

30
qPCR4vir

これは私にとってはうまくいくようです:

NumericType operator |= (NumericType &a, NumericType b) {
    unsigned ai = static_cast<unsigned>(a);
    unsigned bi = static_cast<unsigned>(b);
    ai |= bi;
    return a = static_cast<NumericType>(ai);
}

ただし、enumビットのコレクションのクラスを定義することも検討できます。

class NumericTypeFlags {
    unsigned flags_;
public:
    NumericTypeFlags () : flags_(0) {}
    NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {}
    //...define your "bitwise" test/set operations
};

次に、|および&演算子は代わりにNumericTypeFlagsを返します。

2
jxh

なぜ強く型付けされたのですか?私の本はそれが良い習慣だと言っているので。

次に、あなたの本はあなたのユースケースについて話していません。スコープ指定されていない列挙型は、フラグタイプでは問題ありません。

enum NumericType : int
{
    None                    = 0,

    PadWithZero             = 0x01,
    NegativeSign            = 0x02,
    PositiveSign            = 0x04,
    SpacePrefix             = 0x08
};
0
Caleth

別個の値を組み合わせて新しい未定義の値を作成することで、厳密な型指定のパラダイムと完全に矛盾します。

完全に独立した個別のフラグビットを設定しているようです。この場合、ビットをデータ型に組み合わせても、そのような組み合わせで未定義の値が生成されるのは意味がありません。

フラグデータのサイズを決定する必要があります(charshortlonglong long)と一緒に転がします。ただし、特定のタイプを使用して、フラグをテスト、設定、クリアすることができます。

typedef enum
{
    PadWithZero             = 0x01,
    NegativeSign            = 0x02,
    PositiveSign            = 0x04,
    SpacePrefix             = 0x08
} Flag;

typedef short Flags;

void SetFlag( Flags & flags, Flag f )
{
    flags |= static_cast<Flags>(f);
}

void ClearFlag( Flags & flags, Flag f )
{
    flags &= ~static_cast<Flags>(f);
}

bool TestFlag( const Flags flags, Flag f )
{
    return (flags & static_cast<Flags>)(f)) == static_cast<Flags>(f);
}

これは非常に基本的なもので、各フラグが1ビットのみの場合は問題ありません。マスクされたフラグの場合、それはもう少し複雑です。強く型付けされたクラスにビットフラグをカプセル化する方法はいくつかありますが、それだけの価値があるはずです。あなたの場合、私はそれがそうであるとは確信していません。

0
paddy