问题
How can I overload the |=
operator on a strongly typed (scoped) enum
(in C++11, GCC)?
I want to test, set and clear bits on strongly typed enums. Why strongly typed? Because my books say it is good practice. But this means I have to static_cast<int>
everywhere. To prevent this, I overload the |
and &
operators, but I can't figure out how to overload the |=
operator on an enum. For a class you'd simply put the operator definition in the class, but for enums that doesn't seem to work syntactically.
This is what I have so far:
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));
}
The reason I do this: this is the way it works in strongly-typed C#: an enum there is just a struct with a field of its underlying type, and a bunch of constants defined on it. But it can have any integer value that fits in the enum's hidden field.
And it seems that C++ enums work in the exact same way. In both languages casts are required to go from enum to int or vice versa. However, in C# the bitwise operators are overloaded by default, and in C++ they aren't.
回答1:
inline NumericType& operator |=(NumericType& a, NumericType b)
{
return a= a |b;
}
This works? Compile and run: (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;
}
print 3.
回答2:
This seems to work for me:
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);
}
However, you may still consider defining a class for your collection of enum
bits:
class NumericTypeFlags {
unsigned flags_;
public:
NumericTypeFlags () : flags_(0) {}
NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {}
//...define your "bitwise" test/set operations
};
Then, change your |
and &
operators to return NumericTypeFlags
instead.
回答3:
By combining distinct values to make new, undefined values, you are totally contradicting the strong-typing paradigm.
It looks like you are setting individual flag bits that are completely independent. In this case, it does not make sense to combine your bits into a datatype where such a combination yields an undefined value.
You should decide on the size of your flag data (char
, short
, long
, long long
) and roll with it. You can, however, use specific types to test, set and clear flags:
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);
}
This is very basic, and is fine when each flag is only a single bit. For masked flags, it's a bit more complex. There are ways to encapsulate bit flags into a strongly-typed class, but it really has to be worth it. In your case, I'm not convinced that it is.
来源:https://stackoverflow.com/questions/15889414/how-to-overload-operator-on-scoped-enum