一个enum X : int
(C#)或enum class X : int
(C ++ 11)是具有一个隐藏的内部场类型int
,可容纳任何值。另外,X
在枚举上定义了许多预定义的常量。可以将枚举转换为其整数值,反之亦然。在C#和C ++ 11中都是如此。
在C#中,按照Microsoft的建议,枚举不仅用于保存单个值,而且还用于保存标志的按位组合。此类枚举(通常但并非必须)用[Flags]
属性修饰。为了简化开发人员的工作,按位运算符(OR,AND等)被重载,因此您可以轻松地执行以下操作(C#):
void M(NumericType flags);
M(NumericType.Sign | NumericType.ZeroPadding);
我是一位经验丰富的C#开发人员,但是现在仅对C ++进行了几天的编程,并且不了解C ++约定。我打算以与C#中使用的完全相同的方式使用C ++ 11枚举。在C ++ 11中,作用域枚举上的按位运算符没有重载,因此我想重载它们。
这引发了一场辩论,意见似乎在以下三种选择之间有所不同:
枚举类型的变量用于保存位字段,类似于C#:
void M(NumericType flags); // With operator overloading: M(NumericType::Sign | NumericType::ZeroPadding); // Without operator overloading: M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)));
但这会违背C ++ 11范围枚举的强类型枚举哲学。
如果要存储枚举的按位组合,请使用纯整数:
void M(int flags); M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
但这会将所有内容简化为
int
,从而使您不知道应该在方法中输入哪种类型。编写一个单独的类,该类将重载运算符并将按位标志保存在隐藏的整数字段中:
class NumericTypeFlags { unsigned flags_; public: NumericTypeFlags () : flags_(0) {} NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {} //...define BITWISE test/set operations }; void M(NumericTypeFlags flags); M(NumericType::Sign | NumericType::ZeroPadding);
(全码由user315052)
但是,那么您就没有IntelliSense或任何支持来提示您可能的值。
我知道这是一个主观问题,但是:我应该使用哪种方法?哪种方法(如果有)在C ++中得到最广泛的认可?在处理位字段时,您使用什么方法?为什么?
当然,由于所有这三种方法都有效,因此我正在寻找事实和技术原因,公认的惯例,而不仅仅是个人喜好。
例如,由于我的C#背景,我倾向于使用C ++中的方法1。这还有一个好处,就是我的开发环境可以向我提示可能的值,并且使用重载的枚举运算符可以很容易编写和理解,而且很干净。方法签名清楚地表明了期望的价值。但是这里的大多数人都不同意我,这可能是有充分理由的。
enum E { A = 1, B = 2, C = 4, };
的范围是0..7
(3位)。因此,C ++标准明确保证#1将始终是一个可行的选择。(特别是,除非另有说明,否则enum class
默认为enum class : int
,因此始终具有固定的基础类型。])