通常,人们需要一起使用几种枚举类型.有时,一个人有一个名字冲突.我想到了两种解决方案:使用命名空间,或使用"更大"的枚举元素名称.仍然,命名空间解决方案有两种可能的实现:具有嵌套枚举的虚拟类或完整的命名空间.
我正在寻找这三种方法的优缺点.
例:
// oft seen hand-crafted name clash solution enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd }; enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd }; void setPenColor( const eColors c ) { switch (c) { default: assert(false); break; case cRed: //... break; case cColorBlue: //... //... } } // (ab)using a class as a namespace class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; }; class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; }; void setPenColor( const Colors::e c ) { switch (c) { default: assert(false); break; case Colors::cRed: //... break; case Colors::cBlue: //... //... } } // a real namespace? namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; }; namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; }; void setPenColor( const Colors::e c ) { switch (c) { default: assert(false); break; case Colors::cRed: //... break; case Colors::cBlue: //... //... } }
Drew Dormann.. 66
原创C++ 03回答:
a (over a )的好处是你可以在需要时使用声明.namespace
class
using
使用a 的问题namespace
是命名空间可以在代码中的其他地方扩展.在一个大项目中,你不能保证两个不同的枚举都不会认为它们被调用eFeelings
对于更简单的代码,我使用a struct
,因为你可能希望内容是公开的.
如果您正在进行任何这些实践,那么您就处于领先地位,并且可能不需要进一步仔细检查.
较新的,C++ 11建议:
如果您使用的是C++ 11或更高版本,enum class
则会在枚举名称中隐式调整枚举值的范围.
随着enum class
你将失去隐式转换和比较,以整数类型,但在实践中,可以帮助你暧昧的标志或bug的代码.
原创C++ 03回答:
a (over a )的好处是你可以在需要时使用声明.namespace
class
using
使用a 的问题namespace
是命名空间可以在代码中的其他地方扩展.在一个大项目中,你不能保证两个不同的枚举都不会认为它们被调用eFeelings
对于更简单的代码,我使用a struct
,因为你可能希望内容是公开的.
如果您正在进行任何这些实践,那么您就处于领先地位,并且可能不需要进一步仔细检查.
较新的,C++ 11建议:
如果您使用的是C++ 11或更高版本,enum class
则会在枚举名称中隐式调整枚举值的范围.
随着enum class
你将失去隐式转换和比较,以整数类型,但在实践中,可以帮助你暧昧的标志或bug的代码.
仅供参考我在C++ 0x中有一个新的语法,就像你提到的那样(参见C++ 0x wiki页面)
enum class eColors { ... }; enum class eFeelings { ... };
我将前面的答案与以下内容混合:(编辑:这仅适用于预C++ 11.如果您使用的是C++ 11,请使用enum class
)
我有一个包含所有项目枚举的大头文件,因为这些枚举在工作者类之间共享,将枚举本身放在工作者类中是没有意义的.
该struct
避免市民:语法糖,以及typedef
让你实际上其他工人类中声明这些枚举变量.
我认为使用命名空间根本不会有帮助.也许这是因为我是一名C#程序员,在引用这些值时你必须使用枚举类型名称,所以我已经习惯了.
struct KeySource { typedef enum { None, Efuse, Bbram } Type; }; struct Checksum { typedef enum { None =0, MD5 = 1, SHA1 = 2, SHA2 = 3 } Type; }; struct Encryption { typedef enum { Undetermined, None, AES } Type; }; struct File { typedef enum { Unknown = 0, MCS, MEM, BIN, HEX } Type; };
...
class Worker { File::Type fileType; void DoIt() { switch(fileType) { case File::MCS: ... ; case File::MEM: ... ; case File::HEX: ... ; } }
我肯定会避免使用这个类; 请改用命名空间.问题归结为是使用命名空间还是对枚举值使用唯一ID.就个人而言,我会使用命名空间,以便我的ID可以更短,并希望更加不言自明.然后,应用程序代码可以使用"using namespace"指令,使所有内容更具可读性.
从上面的例子:
using namespace Colors; void setPenColor( const e c ) { switch (c) { default: assert(false); break; case cRed: //... break; case cBlue: //... //... } }
使用类或命名空间之间的区别在于,无法像命名空间那样重新打开类.这避免了将来可能滥用命名空间的可能性,但也存在无法添加到枚举集的问题.
使用类的一个可能的好处是它们可以用作模板类型参数,而名称空间不是这种情况:
class Colors { public: enum TYPE { Red, Green, Blue }; }; templatevoid foo (T t) { typedef typename T::TYPE EnumType; // ... }
就个人而言,我不是一个风扇使用,而我更喜欢完全合格的名字,所以我真的不认为这是对命名空间的加分.但是,这可能不是您在项目中做出的最重要的决定!
使用类的好处是你可以在它上面构建一个完整的类.
#includeclass Color { public: typedef enum { Red, Blue, Green, Yellow } enum_type; private: enum_type _val; public: Color(enum_type val = Blue) : _val(val) { assert(val <= Yellow); } operator enum_type() const { return _val; } }; void SetPenColor(const Color c) { switch (c) { case Color::Red: // ... break; } }
如上例所示,通过使用类,您可以:
禁止(遗憾的是,不是编译时)C++允许从无效值转换,
为新创建的枚举设置(非零)默认值,
添加更多方法,例如返回选择的字符串表示.
请注意,您需要声明,operator enum_type()
以便C++知道如何将您的类转换为基础枚举.否则,您将无法将类型传递给switch
语句.
由于枚举的范围是它们的封闭范围,因此最好将它们包装在某些内容中以避免污染全局命名空间并帮助避免名称冲突.我更喜欢命名空间,因为namespace
感觉就像一个持有的包,而class
感觉就像一个健壮的对象(参见struct
与class
辩论).命名空间的一个可能的好处是它可以在以后扩展 - 如果您正在处理无法修改的第三方代码,则非常有用.
当我们使用C++ 0x获取枚举类时,这当然都没有用.