4

C++ でこの問題があります:値が列挙型から取得されるビットフィールドを型定義できますか?

コードはより説明的になります:

typedef {
 AUDIO    = 0x01,
 VIDEO    = 0x02,
 SUBTITLE = 0x04,
 DATA     = 0x08,
 GUARD,
 ALL      = 0xFF
} my_enum_e;

// I'd like to replace 'unsigned int' by 'my_enum_e' or similar
int myFunction( unsigned int mask ) 
{
  // code
}

// called like this:
myFunction( AUDIO|VIDEO|DATA );

関数のプロトタイプでは、入力値の型として使用したいと思いmy_enum_eます。これにより、コードを調べたときに、そこに入力する必要がある値をすぐに知ることができます。

さて、プロトタイプを

int myFunction( my_enum_e mask );

キャストエラーについてコンパイラに泣き言を言わせます。次のように関数呼び出しをキャストしても修正できません。

int myFunction( my_enum_e mask )
{
    // code
}

myFunction( (my_enum_e)(VIDEO|AUDIO|DATA) );

しかし、これは非常に恐ろしいことであり、合法であるかどうかさえわかりません (値が切り捨てられるのでしょうか??)。
解決策はありますか?

4

5 に答える 5

4

|および場合によっては他の演算子の明示的なオーバーロードを追加します。

my_enum_e operator|(my_enum_e a, my_enum_e b) 
    { return my_enum_e(unsigned(a)|unsigned(b)); }

特定のビットマスク タイプに必要なすべての演算子を定義するマクロを作成できます。

#define BITMASK_OPERATORS(T)   T operator|(T a, T b) { return T(unsigned(a)|unsigned(b)); } \
                                 T operator^(T a, T b) ...
于 2012-07-23T14:13:17.287 に答える
2

これに対処するための特別な関数を実装するのはどうですか:

template <typename Enum>
Enum bitField(unsigned bits) {
  return static_cast<Enum>(bits);
}

あなたがしていることに表現力を追加します。

myFunction(bitField<my_enum_e>(VIDEO|AUDIO|DATA));

より洗練されたものが必要な場合は、次のようにすることができます。

template <typename Enum>
struct BitField {
  Enum value;
  BitField(Enum value) : value(value) {}
  BitField operator|(Enum more) {
    return BitField(value | more);
  }
  BitField operator&(Enum more) {
    return BitField(value & more);
  }
  BitField operator~() {
    return BitField(~value);
  }
  operator Enum() {
    return value;
  }
}

これにより、書き込みが可能になります

myFunction(BitField<my_enum_e>(VIDEO) | AUDIO | DATA);
于 2012-07-23T14:06:11.070 に答える
0

このスレッドを確認することをお勧めします: C++ で使用しているタイプセーフな列挙型は? - [Boost Vault] (ファイル名enum_rev4.6.zip) で言及されている実装。1は、次を宣言する可能性も提供しますBOOST_BITFIELD

BOOST_BITFIELD(my_enum_e, 
  (AUDIO)    (0x01)
  (VIDEO)    (0x02)
  (SUBTITLE) (0x04)
  (DATA)     (0x08)
);

その後、関数を宣言できます。

int myFunction( const my_enum_e & in_enum ) 
{
  if ( in_enum[AUDIO] ) ...
}

その時の使い方は

void callerFunction()
{
  my_enum_e mask;
  mask.set(my_enum_e::AUDIO);
  mask.set(my_enum_e::VIDEO | my_enum_e::SUBTITLE );
  cout << mask << " = " << hex << mask.value() << endl; // will print: AUDIO|VIDEO|SUBTITLE = 0x7
  myFunction( mask );

}

API のドキュメントはあまりよくありません。ただし、パッケージには、いくつかの使用法を示すテストが付属しています。

于 2012-07-23T17:59:40.553 に答える
0

ビット演算を実行すると、コンパイラはVIDEO|AUDIO|DATAを整数値と見なすため、*my_enum_e* でキャストする必要があります。

于 2012-07-23T14:00:29.043 に答える
-2

これを回避する 1 つの方法は、typedef int MY_FLAGS;代わりにすべての値を #define することです: #define AUDIO 0x01など. そうすれば、コンパイラはうめき声を上げず、関数呼び出しで型を取得できます:

int myFunction( MY_FLAGS mask );

myFunction( VIDEO|AUDIO|DATA );
于 2012-07-23T14:08:05.047 に答える