如何在强类型(作用域)|=
(在C ++ 11,GCC中)重载enum
运算符?
我想在强类型枚举上测试,设置和清除位。为何选择强类型?因为我的书说这是好习惯。但这意味着我到处都要static_cast<int>
。为了防止这种情况,我对|
和&
运算符进行了重载,但我无法弄清楚如何在枚举上重载|=
运算符。对于一个类,你只需要放置the operator definition in the class,但对于那些似乎不能在语法上工作的枚举。
这是我到目前为止所做的:
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 ++中,它们不会重载。
答案 0 :(得分:29)
inline NumericType& operator |=(NumericType& a, NumericType b)
{
return a= a |b;
}
这有效吗? 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;
}
打印3。
答案 1 :(得分:2)
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 :(得分:1)
我厌倦了所有带有枚举运算的样板文件,转而使用更像这样的习语:
struct NumericType {
typedef uint32_t type;
enum : type {
None = 0,
PadWithZero = 0x01,
NegativeSign = 0x02,
PositiveSign = 0x04,
SpacePrefix = 0x08
};
};
为了清楚起见,我仍然可以通过这种方式传递 NumericType::type
参数,但我牺牲了类型安全性。
我考虑制作一个通用模板类来代替 uint32_t
,它会提供算术重载的一个副本,但显然我不允许从类,所以无论如何(感谢 C++!)。
答案 3 :(得分:0)
通过组合不同的值来创建新的,未定义的值,你完全与强类型范式相矛盾。
看起来您正在设置完全独立的单个标志位。在这种情况下,将您的位组合成一种数据类型是没有意义的,这种组合产生一个未定义的值。
您应该决定标志数据的大小(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);
}
这是非常基本的,当每个标志只有一个位时就可以了。对于蒙面标志,它有点复杂。有一些方法可以将位标志封装到强类型类中,但它确实值得。在你的情况下,我不相信它是。
答案 4 :(得分:0)
为什么要强键入?因为我的书说这是一种好习惯。
然后,您的书中没有在谈论您的用例。对于标志类型,无范围枚举是很好的选择。
enum NumericType : int
{
None = 0,
PadWithZero = 0x01,
NegativeSign = 0x02,
PositiveSign = 0x04,
SpacePrefix = 0x08
};