匿名enum
声明的目的是什么,例如:
enum { color = 1 };
为什么不宣布int color = 1
?
答案 0 :(得分:80)
这是declaring a compile-time integer constant所谓的枚举技巧。它的优点是它保证不会实例化变量,因此没有运行时开销。无论如何,大多数编译器都没有引入整数常量的开销。
答案 1 :(得分:55)
枚举不会占用任何空间并且是不可变的。
如果您使用const int color = 1;
,那么您将解决可变性问题,但如果有人使用color
(const 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
enum
和const 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)