等效于作用域枚举的"using namespace X"?

Equivalent of "using namespace X" for scoped enumerations?

本文关键字:using namespace 作用域 枚举      更新时间:2023-10-16

我正在使用作用域枚举来枚举我正在实现的某个状态机中的状态。例如,让我们说这样的话:

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,然后就进入内部。强类型enums也是如此。

C++20添加了using enum X语法,它看起来就是这样。

当然,您可以不使用enum class语法,只使用常规的enums。但是,您将失去强类型。

需要注意的是,对弱类型枚举使用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
}