我正在使用作用域枚举来枚举我正在实现的某个状态机中的状态。例如,让我们说:
enum class CatState
{
sleeping,
napping,
resting
};
在我定义状态转换表的cpp文件中,我想使用等同于using namespace X
的东西,这样我就不需要在CatState::
前添加所有州名。换句话说,我想使用sleeping
代替CatState::sleeping
。我的转换表有很多列,因此避免使用CatState::
前缀会使事情变得更紧凑和可读。
那么,有没有办法避免一直输入CatState::
?
是的,是的,我已经意识到using namespace
的陷阱。如果有一个强类型枚举的等价物,我保证只在我的cpp实现文件的有限范围内使用它,而不是邪恶。
答案 0 :(得分:15)
那么,有没有办法避免一直输入
CatState::
?
没有。正如没有必要为静态类成员键入ClassName::
一样。你不能说using typename ClassName
然后进入内部。强类型enum
s也是如此。
您当然不能使用enum class
语法,只需使用常规enum
。但是你失去了强烈的打字。
应该注意的是,对于弱类型枚举使用ALL_CAPS的原因之一是避免名称冲突。一旦我们有完整的作用域和强类型,枚举的名称是唯一标识的,不能与其他名称冲突。能够将这些名称带入命名空间范围将重新引入此问题。因此,您可能希望再次使用ALL_CAPS来帮助消除名称歧义。
答案 1 :(得分:15)
因此简短的答案是“否”,但是幸运的是,这将在最近完成的C ++ 20功能集中改变。根据此accepted proposal,您将可以执行以下操作:
enum class CatState
{
sleeping,
napping,
resting
};
std::string getPurr(CatState state)
{
switch (state)
{
using enum CatState;
// our states are accessible without the scope operator from now on
case sleeping: return {}; // instead of "case CatState::sleeping:"
case napping: return "purr";
case resting: return "purrrrrr";
}
}
答案 2 :(得分:8)
您可以考虑使用typedef
来缩短限定名称:
typedef CatState C;
或者,如果列的重复方式可以轻松生成,您可以考虑使用宏来生成表中的每一行,这样可以生成非常简洁(也更容易阅读)的代码。
答案 3 :(得分:2)
Nicol的回答是正确的:该语言旨在让您始终限定范围内的枚举数(enum { }
范围本身除外)。
然而,here is a technique我提出了在所选类中未对比的“范围”枚举器。从技术上讲,枚举数是无范围的,因此它们仍然会隐式转换为int
。 (并不像你所说的那样“强类型”。)然而,在成语中,在真正的enum
名称之后使用范围运算符访问它们,所以语法上没有区别 - 因此它需要C + 11。
#define IMPORTABLE_ENUM( TYPENAME, ... ) \
\
struct import_ ## TYPENAME { \
enum TYPENAME { \
__VA_ARGS__ \
}; \
}; \
\
typedef import_ ## TYPENAME :: TYPENAME TYPENAME;
// usage:
IMPORTABLE_ENUM ( duck, huey, dewey, louie )
duck d = duck::dewey; // can't use unscoped enumerators here
struct duck_madness : private import_duck { // but inside a derived class
duck who_did_it() { return huey; } // qualification is unnecessary
};
答案 4 :(得分:2)
我也很想有这种可能性,我觉得这个限制非常烦人。通常最好让程序员决定他想要使用哪些功能。无论是显式范围还是更方便的方式。如果你限制程序员,他将放弃整个功能,以方便或发明丑陋的变通方法,如下面的基于模板的类型安全枚举。在没有优化的情况下编译时会有一些开销。
template<class _Enum>
class type_safe_enum
{
private:
_Enum m_EnumValue;
operator int();
public:
inline operator _Enum() const { return m_EnumValue; }
inline void operator =(_Enum x) { m_EnumValue = x; }
};
enum _MY_ENUM
{
Value1,
Value2
};
enum _MY_ENUM2
{
Value3,
Value4
};
typedef type_safe_enum<_MY_ENUM> MY_ENUM;
void TestMyEnum()
{
MY_ENUM myEnum;
int x;
myEnum = Value1; // ok
// myEnum = Value3; // compilation error
// myEnum = 0; // compilation error
// x = myEnum; // compilation error
}