等效于作用域枚举的"using namespace X"?
Equivalent of "using namespace X" for scoped enumerations?
我正在使用作用域枚举来枚举我正在实现的某个状态机中的状态。例如,让我们说这样的话:
enum class CatState
{
sleeping,
napping,
resting
};
在我定义状态转换表的cpp文件中,我想使用等效于using namespace X
的东西,这样我就不需要在所有状态名称前面加上CatState::
。换句话说,我想使用sleeping
而不是CatState::sleeping
。我的转换表有相当多的列,因此避免使用CatState::
前缀可以使内容更加紧凑和可读。
那么,有没有办法避免一直键入CatState::
?
是的,是的,我已经意识到using namespace
的陷阱。如果有强类型枚举的等价物,我保证只在cpp实现文件中的有限范围内使用它,而不是用于邪恶
那么,有没有办法避免一直键入
CatState::
?
在C++20之前没有。正如对于静态类成员,不存在必须键入ClassName::
的等价项一样。你不能说using typename ClassName
,然后就进入内部。强类型enum
s也是如此。
C++20添加了using enum X
语法,它看起来就是这样。
当然,您可以不使用enum class
语法,只使用常规的enum
s。但是,您将失去强类型。
需要注意的是,对弱类型枚举使用ALL_CAPS的原因之一是为了避免名称冲突。一旦我们有了完整的作用域和强类型,枚举的名称就会被唯一标识,并且不能与其他名称冲突。能够将这些名称引入命名空间范围将重新引入这个问题。因此,您可能希望再次使用ALL_CAPS来帮助消除名称的歧义。
所以简短的答案是否定的,但幸运的是,这将在最近完成的C++20特性集中发生变化。根据此已接受的建议,您将能够执行以下操作:
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";
}
}
您可以考虑使用typedef
来缩短限定名称:
typedef CatState C;
或者,如果列是重复的,可以很容易地生成,您可以考虑使用宏来生成表中的每一行,这样可以生成非常简洁(更容易阅读)的代码。
Nicol的答案是正确的:该语言旨在使您始终限定作用域枚举器(enum { }
作用域本身除外)。
然而,这里有一种我为"作用域"枚举器提出的技术,这些枚举器在所选的类中不受作用域限制。从技术上讲,枚举器是无范围的,因此它们仍将隐式转换为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
};
我也很想有这种可能性,我觉得这种限制很烦人。通常最好让程序员决定他想使用哪些功能。要么是明确的范围界定,要么是更方便的方式。如果你限制程序员,他要么为了方便而放弃整个功能,要么发明丑陋的解决方案,比如下面基于模板的类型安全枚举。如果在没有优化的情况下进行编译,它将有一些开销。
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
}
- "using namespace std;"在C++的作用是什么?
- 为什么我需要做'using namespace std'而不是"使用 std::cout"?
- 'using namespace'实现细节的便捷方法(仅标头库)?
- C++中"typedef"、"using"、"namespace"和"using namespace"有什么区别?
- "using namespace"子句在什么范围内有效?
- 如何找到"using namespace std"的违规用法?
- 在实现文件中,我们应该更喜欢"using namespace"指令还是将实现包装在命名空间 { } 中?
- 如何根据对象名称将'using namespace'添加到类定义中?
- 没有任何 #include "using namespace std;"?
- 用于定义全局函数"using namespace"
- 'using namespace'如何在C++运作
- 为什么我们应该在使用"using namespace std"时使用"#include<iostream>"?
- 如何在代码中使用 STD 而不包含"using namespace std"?
- 如何正确使用"using namespace foo?"
- 使用不带前缀"std"且不带"using namespace std;"的 std::sort() 成功编译
- 总是"using namespace std" ?
- 头文件中可以包含"using namespace"语句吗?
- 为什么以及如何"using namespace"声明会混淆C++中的编译器?
- "using namespace std;"是否免于过多代码规则?
- C++如何知道在哪里查找使用 "using namespace ..." 指定的命名空间?