C++ 枚举类型的命名空间 - 最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/482745/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
namespaces for enum types - best practices
提问by xtofl
Often, one needs several enumerated types together. Sometimes, one has a name clash. Two solutions to this come to mind: use a namespace, or use 'larger' enum element names. Still, the namespace solution has two possible implementations: a dummy class with nested enum, or a full blown namespace.
通常,需要将多个枚举类型放在一起。有时,一个人会发生名称冲突。我想到了两个解决方案:使用命名空间,或使用“更大”的枚举元素名称。尽管如此,命名空间解决方案有两种可能的实现:一个带有嵌套枚举的虚拟类,或者一个完整的命名空间。
I'm looking for pros and cons of all three approaches.
我正在寻找所有三种方法的优缺点。
Example:
例子:
// 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: //...
//...
}
}
采纳答案by Drew Dormann
Original C++03 answer:
原始 C++03 答案:
The benefitfrom a namespace
(over a class
) is that you can use using
declarations when you want.
a (over a )的好处是您可以在需要时使用声明。namespace
class
using
The problemwith using a namespace
is that namespaces can be expanded elsewhere in the code. In a large project, you would not be guaranteed that two distinct enums don't both think they are called eFeelings
使用 a的问题namespace
是命名空间可以在代码的其他地方扩展。在一个大型项目中,您不能保证两个不同的枚举不会都认为它们被称为eFeelings
For simpler-looking code, I use a struct
, as you presumably want the contents to be public.
对于看起来更简单的代码,我使用 a struct
,因为您可能希望内容是公开的。
If you're doing any of these practices, you are ahead of the curve and probably don't need to scrutinize this further.
如果您正在执行这些实践中的任何一个,那么您就处于领先地位,并且可能不需要进一步这一点。
Newer, C++11 advice:
较新的 C++11 建议:
If you are using C++11 or later, enum class
will implicitly scope the enum values within the enum's name.
如果您使用 C++11 或更高版本,enum class
将隐式地限定枚举名称内的枚举值。
With enum class
you will lose implicit conversions and comparisons to integer types, but in practice that may help you discover ambiguous or buggy code.
随着enum class
你将失去隐式转换和比较,以整数类型,但在实践中,可以帮助你发现歧义或bug的代码。
回答by jmihalicza
FYI In C++0x there is a new syntax for cases like what you mentioned (see C++0x wiki page)
仅供参考在 C++0x 中,对于您提到的情况有一种新的语法(请参阅C++0x wiki 页面)
enum class eColors { ... };
enum class eFeelings { ... };
回答by Mark Lakata
I've hybridized the preceding answers to something like this: (EDIT: This is only useful for pre- C++11. If you are using C++11, use enum class
)
我已经将前面的答案与以下内容混合在一起:(编辑:这仅对 C++11 之前的版本有用。如果您使用的是 C++11,请使用enum class
)
I've got one big header file that contains all my project enums, because these enums are shared between worker classes and it doesn't make sense to put the enums in the worker classes themselves.
我有一个包含我所有项目枚举的大头文件,因为这些枚举在工作类之间共享,将枚举放在工作类本身中是没有意义的。
The struct
avoids the public: syntactic sugar, and the typedef
lets you actually declare variables of these enums within other worker classes.
该struct
避免市民:语法糖,以及typedef
让你实际上其他工人类中声明这些枚举变量。
I don't think using a namespace helps at all. Maybe this is because I'm a C# programmer, and there you haveto use the enum type name when referring the values, so I'm used to it.
我认为使用命名空间根本没有帮助。也许这是因为我是一个 C# 程序员,在那里引用值时必须使用 enum 类型名称,所以我已经习惯了。
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: ... ;
}
}
回答by Charles Anderson
I would definitely avoid using a class for this; use a namespace instead. The question boils down to whether to use a namespace or to use unique ids for the enum values. Personally, I'd use a namespace so that my ids could be shorter and hopefully more self-explanatory. Then application code could use a 'using namespace' directive and make everything more readable.
我绝对会避免为此使用类;改用命名空间。问题归结为是使用命名空间还是为枚举值使用唯一的 id。就我个人而言,我会使用一个命名空间,这样我的 id 就可以更短,并且希望更容易解释。然后应用程序代码可以使用“使用命名空间”指令并使所有内容更具可读性。
From your example above:
从你上面的例子:
using namespace Colors;
void setPenColor( const e c ) {
switch (c) {
default: assert(false);
break; case cRed: //...
break; case cBlue: //...
//...
}
}
回答by Richard Corden
An difference between using a class or a namespace is that the class cannot be reopened like a namespace can. This avoids the possibility that the namespace might be abused in the future, but there is also the problem that you cannot add to the set of enumerations either.
使用类或命名空间的区别在于类不能像命名空间那样重新打开。这避免了名称空间将来可能被滥用的可能性,但也存在无法添加到枚举集的问题。
A possible benefit for using a class, is that they can be used as template type arguments, which is not the case for namespaces:
使用类的一个可能的好处是它们可以用作模板类型参数,而命名空间则不然:
class Colors {
public:
enum TYPE {
Red,
Green,
Blue
};
};
template <typename T> void foo (T t) {
typedef typename T::TYPE EnumType;
// ...
}
Personally, I'm not a fan of using, and I prefer the fully qualified names, so I don't really see that as a plus for namespaces. However, this is probably not the most important decision that you'll make in your project!
就我个人而言,我不喜欢使用,我更喜欢完全限定的名称,所以我并不认为这是命名空间的一个优点。但是,这可能不是您将在项目中做出的最重要的决定!
回答by Micha? Górny
Advantage of using a class is that you can build a full-fledged class on top of it.
使用类的优点是您可以在它之上构建一个成熟的类。
#include <cassert>
class 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;
}
}
As the above example shows, by using a class you can:
如上例所示,通过使用类,您可以:
- prohibit (sadly, not compile-time) C++ from allowing a cast from invalid value,
- set a (non-zero) default for newly-created enums,
- add further methods, like for returning a string representation of a choice.
- 禁止(遗憾的是,不是编译时)C++ 允许从无效值进行强制转换,
- 为新创建的枚举设置(非零)默认值,
- 添加更多方法,例如返回选择的字符串表示。
Just note that you need to declare operator enum_type()
so that C++ would know how to convert your class into underlying enum. Otherwise, you won't be able to pass the type to a switch
statement.
请注意,您需要声明,operator enum_type()
以便 C++ 知道如何将您的类转换为底层枚举。否则,您将无法将类型传递给switch
语句。
回答by Michael Kristofik
Since enums are scoped to their enclosing scope, it's probably best to wrap them in somethingto avoid polluting the global namespace and to help avoid name collisions. I prefer a namespace to class simply because namespace
feels like a bag of holding, whereas class
feels like a robust object (cf. the struct
vs. class
debate). A possible benefit to a namespace is that it can be extended later - useful if you're dealing with third-party code that you cannot modify.
由于枚举的范围限定在它们的封闭范围内,因此最好将它们包装在一些东西中以避免污染全局命名空间并帮助避免名称冲突。我更喜欢命名空间而不是类,因为namespace
感觉就像一个袋子,而class
感觉就像一个健壮的对象(参见struct
vs.class
辩论)。命名空间的一个可能的好处是它可以在以后扩展 - 如果您正在处理无法修改的第三方代码,这很有用。
This is all moot of course when we get enum classes with C++0x.
当我们使用 C++0x 获得枚举类时,这当然毫无意义。
回答by Matthieu M.
I also tend to wrap my enums in classes.
我也倾向于在类中包装我的枚举。
As signaled by Richard Corden, the benefit of a class is that it is a type in the c++ sense and so you can use it with templates.
正如 Richard Corden 所指出的,类的好处是它是 C++ 意义上的一种类型,因此您可以将它与模板一起使用。
I have special toolbox::Enum class for my needs that I specialize for every templates which provides basic functions (mainly: mapping an enum value to a std::string so that I/O are easier to read).
我有特殊的 toolbox::Enum 类可以满足我的需要,我专门用于提供基本功能的每个模板(主要是:将枚举值映射到 std::string 以便 I/O 更易于阅读)。
My little template also has the added benefit of really checking for the allowed values. The compiler is kind of lax on checking if the value really is in the enum:
我的小模板还有一个额外的好处,那就是真正检查允许的值。编译器在检查值是否真的在枚举中时有点松懈:
typedef enum { False: 0, True: 2 } boolean;
// The classic enum you don't want to see around your code ;)
int main(int argc, char* argv[])
{
boolean x = static_cast<boolean>(1);
return (x == False || x == True) ? 0 : 1;
} // main
It always bothered me that the compiler will not catch this, since you are left with an enum value that has no sense (and that you won't expect).
编译器不会捕捉到这一点总是让我感到困扰,因为您留下了一个没有意义的枚举值(并且您不会期望)。
Similarly:
相似地:
typedef enum { Zero: 0, One: 1, Two: 2 } example;
int main(int argc, char* argv[])
{
example y = static_cast<example>(3);
return (y == Zero || y == One || y == Two) ? 0 : 1;
} // main
Once again main will return an error.
main 将再次返回错误。
The problem is that the compiler will fit the enum in the smallest representation available (here we need 2 bits) and that everything that fits in this representation is considered a valid value.
问题是编译器会在可用的最小表示中适合枚举(这里我们需要 2 位),并且适合这种表示的所有内容都被认为是有效值。
There is also the problem that sometimes you'd rather have a loop on the possible values instead of a switch so that you don't have to modify all you switches each time you add a value to the enum.
还有一个问题是,有时您宁愿在可能的值上循环而不是开关,这样您就不必在每次向枚举添加值时修改所有开关。
All in all my little helper really ease things for my enums (of course, it adds some overhead) and it is only possible because I nest each enum in its own struct :)
总而言之,我的小助手确实为我的枚举减轻了负担(当然,它增加了一些开销),这只是因为我将每个枚举嵌套在自己的结构中:)