匿名枚举的用法

时间:2011-08-22 11:47:47

标签: c++ enums

匿名enum声明的目的是什么,例如:

enum { color = 1 };

为什么不宣布int color = 1

8 个答案:

答案 0 :(得分:80)

这是declaring a compile-time integer constant所谓的枚举技巧。它的优点是它保证不会实例化变量,因此没有运行时开销。无论如何,大多数编译器都没有引入整数常量的开销。

答案 1 :(得分:55)

枚举不会占用任何空间并且是不可变的。

如果您使用const int color = 1;,那么您将解决可变性问题,但如果有人使用colorconst int* p = &color;)的地址,则必须分配空间。这可能不是什么大问题,但除非您明确希望人们能够获取color的地址,否则您可能会阻止它。

同样,当在类中声明一个常量字段时,它必须是static const (对于现代C ++而言不是这样)并且并非所有编译器都支持静态const成员的内联初始化。 / p>


免责声明:此答案不应被视为对所有数字常量使用enum的建议。你应该做你(或你的牛人)认为更具可读性的事情。答案只列出了可能更喜欢使用enum的一些原因。

答案 2 :(得分:6)

如果这是旧代码,则enum可能已被用于“枚举黑客”。

您可以在此链接中了解有关“枚举黑客”的更多信息:enum hack

答案 3 :(得分:4)

(1) int color = 1;

color可以改变(意外)。

(2) enum { color = 1 };

color无法更改。

enum的另一个选项是,

const int color = 1;  // 'color' is unmutable

enumconst int都提供完全相同的概念;这是一个选择问题。关于enum节省空间的普遍看法,IMO没有与此相关的内存约束,编译器足够聪明,可以在需要时优化const int

[注意:如果有人试图在const_cast<>上使用const int;它会导致未定义的行为(这很糟糕)。但是,enum无法做到这一点。所以我个人最喜欢的是enum]

答案 4 :(得分:4)

这种情况的一个用途是当你进行模板元编程时,因为枚举对象不是左值,而static const成员是。它也曾经是编译器的常用解决方法,它不允许在类定义中初始化静态积分常量。这在another question中解释。

答案 5 :(得分:1)

使用时  enum {color = 1}
 你没有使用任何记忆  #define color 1

如果您声明变量
 int color=1  然后你会占用内存以获得一个不可更改的值。

答案 6 :(得分:0)

我没有看到它提到,另一个用途是限制你的常量。我目前正在处理使用Visual Studio 2005编写的代码,现在它已移植到android-g ++。在VS2005中,您可以使用此enum MyOpts { OPT1 = 1 };之类的代码并将其用作MyOpts :: OPT1 - 并且编译器没有抱怨它,即使它无效。 g ++将此类代码报告为错误,因此一种解决方案是使用匿名枚举,如下所示:struct MyOpts { enum {OPT1 =1}; };,现在两个编译器都很满意。

答案 7 :(得分:0)

答案

可读性和性能。
详细信息描述为以下示例的注释。

用例

个人示例

Unreal Engine 4(C ++游戏引擎)中,我具有以下属性(引擎公开的成员变量):

/// Floor Slope.

UPROPERTY
(
    Category = "Movement",
    VisibleInstanceOnly,

    BlueprintGetter = "BP_GetFloorSlope",
    BlueprintReadOnly,

    meta =
    (
        ConsoleVariable = "Movement.FloorSlope",
        DisplayName     = "Floor Slope",
        ExposeOnSpawn   = true,
        NoAutoLoad
    )
)

float FloorSlope = -1.f;

这是播放器站立的地面坡度值(值∈[0; 90)°)(如果有)。
由于引擎的限制,它既不能是std::optional也不能是TOptional
我想出了一个解决方案,可以添加另一个自解释变量bIsOnFloor

bool  bIsOnFloor = false;

我的FloorSlope的仅C ++内部设置器采用以下形式:

void UMovement::SetFloorSlope(const float& FloorSlope) noexcept
    contract [[expects audit: FloorSlope >= 0._deg && FloorSlope < 90._deg]]
{
    this->bIsOnFloor = true;
    this->FloorSlope = FloorSlope;

    AUI::UI->Debug->FloorSlope = FString::Printf(L"Floor Slope: %2.0f", FloorSlope);
};

添加特殊情况,即很难猜测FloorSlope参数将使用-1.f作为参数,而且也不方便使用。 相反,我宁愿创建False enum字段:

enum { False };

这样,我可以简单地重载需要直观的SetFloorSlope而不是False的{​​{1}}函数。

-1.f


当玩家角色在刻上向其施加重力时撞到地板时,我只需打:

void UMovement::SetFloorSlope([[maybe_unused]] const decltype(False)&) noexcept
{
    this->bIsOnFloor = false;
    this->FloorSlope = -1.f;

    AUI::UI->Debug->FloorSlope = L"Floor Slope:  —";
};

…,其中SetFloorSlope(FloorSlope); FloorSlope值∈[0; 90)°。 否则(如果它没有跌落),我打电话:

float

这种形式(而不是传递SetFloorSlope(False); )更具可读性,并且易于解释。

引擎示例

另一个示例可能是阻止或强制初始化。 上面提到的虚幻引擎4通常使用FHitResult -1.f,其中包含有关轨迹的一次命中的信息,例如撞击点和该点的表面法线。

此复杂的struct默认情况下调用struct方法,为某些成员变量设置一些值。这可以被强制执行或被阻止(公共文档:FHitResult #constructor):

Init

Epic Games定义了类似的FHitResult() { Init(); } explicit FHitResult(float InTime) { Init(); Time = InTime; } explicit FHitResult(EForceInit InInit) { Init(); } explicit FHitResult(ENoInit NoInit) { } ,但添加了多余的enum名称:

enum

enum EForceInit { ForceInit, ForceInitToZero }; enum ENoInit {NoInit}; 传递给NoInit的构造函数会阻止初始化,这可能会由于不初始化将在其他地方初始化的值而导致性能提高。

社区示例

综合游戏能力分析系列中的

FHitResult用法在DamirH的post中:

FHitResult(NoInit)