如何在scoped enum上重载| =运算符?

时间:2013-04-08 21:34:12

标签: c++ c++11 enums operator-overloading bitwise-operators

如何在强类型(作用域)|= (在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 ++中,它们不会重载。

5 个答案:

答案 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)

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);
}

但是,您仍可以考虑为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)

通过组合不同的值来创建新的,未定义的值,你完全与强类型范式相矛盾。

看起来您正在设置完全独立的单个标志位。在这种情况下,将您的位组合成一种数据类型是没有意义的,这种组合产生一个未定义的值。

您应该决定标志数据的大小(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);
}

这是非常基本的,当每个标志只有一个位时就可以了。对于蒙面标志,它有点复杂。有一些方法可以将位标志封装到强类型类中,但它确实值得。在你的情况下,我不相信它是。

答案 4 :(得分:0)

为什么要强键入?因为我的书说这是一种好习惯。

然后,您的书中没有在谈论您的用例。对于标志类型,无范围枚举是很好的选择。

enum NumericType : int
{
    None                    = 0,

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