Как перегрузить оператор |= на перечисление с областью действия?
Как я могу перегрузить оператор |=
на строго типизированном (scoped) enum
(в C++11, GCC)?
Я хочу протестировать, установить и очистить биты на строго типизированных перечислениях. Почему сильно набрано? Потому что мои книги говорят, что это хорошая практика. Но это означает, что я должен static_cast<int>
везде. Чтобы предотвратить это, я перегружаю операторы |
и &
, но я не могу понять, как перегружать оператор |=
на перечисление. Для класса вы бы просто поместили определение оператора в класс , но для перечислений, которые, похоже, не работают синтаксически.
Вот что у меня есть до сих пор:
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++ работают точно так же. В обоих языках приведения должны идти от перечисления к int или наоборот. Однако в C# побитовые операторы по умолчанию перегружены, а в C++ - нет.
3 ответа:
inline NumericType& operator |=(NumericType& a, NumericType b) { return a= a |b; }
Это работает? компиляция и запуск: (Ideone)
#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.
Комбинируя различные значения для создания новых, неопределенных значений, вы полностью противоречите парадигме строгого типирования.
Похоже, что вы устанавливаете отдельные биты флага, которые полностью независимы. В этом случае не имеет смысла объединять ваши биты в тип данных, где такая комбинация дает неопределенное значение.
Вам следует определиться с размером данных флага.(
char
,short
,long
,long 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); }
Это очень просто, и прекрасно, когда каждый флаг-это только один бит. Для замаскированных флагов это немного сложнее. Есть способы инкапсулировать битовые флаги в строго типизированный класс, но это действительно того стоит. В вашем случае я не уверен, что это так.
Это, кажется, работает для меня:
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 };
Затем измените операторы
|
и&
на returnNumericTypeFlags
.