C++ 匿名枚举的使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7147008/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
The usage of anonymous enums
提问by sharptooth
What is the purpose of anonymous enum
declarations such as:
匿名enum
声明的目的是什么,例如:
enum { color = 1 };
Why not just declare int color = 1
?
为什么不直接声明int color = 1
?
采纳答案by Motti
Enums don't take up any space and are immutable.
枚举不占用任何空间并且是不可变的。
If you used const int color = 1;
then you would solve the mutability issue but if someone took the address of color
(const int* p = &color;
) then space for it would have to be allocated. This may not be a big deal but unless you explicitly wantpeople to be able to take the address of color
you might as well prevent it.
如果您使用,const int color = 1;
那么您将解决可变性问题,但如果有人使用color
( const int* p = &color;
)的地址,则必须为其分配空间。这可能没什么大不了的,但除非您明确希望人们能够获取color
您的地址,否则不妨阻止它。
Also when declaring a constant field in a class then it will have to be static const
(not true for modern C++)and not all compilers support inline initialization of static const members.
同样,当在类中声明一个常量字段时,它必须是static const
(对于现代 C++ 不是这样)并且并非所有编译器都支持静态常量成员的内联初始化。
Disclaimer:This answer should not be taken as advice to use enum
for all numeric constants. You should do what you (or your co-workers) think is more readable. The answer just lists some reasons one mightprefer to use an enum
.
免责声明:不应将此答案视为enum
用于所有数字常量的建议。你应该做你(或你的同事)认为更具可读性的事情。答案只是列出了人们可能更喜欢使用enum
.
回答by sharptooth
That's a so-called enum trick for declaring a compile-time integer constant. It's advantage is it guarantees that no variable is instantiated and therefore there's no runtime overhead. Most compilers introduce no overhead with integer constants anyway.
这是用于声明编译时整数常量的所谓枚举技巧。它的优点是它保证没有变量被实例化,因此没有运行时开销。无论如何,大多数编译器都不会引入整数常量的开销。
回答by Eran Zimmerman
回答by R. Martinho Fernandes
One use of this is when you're doing template metaprogramming, because enum objects are not lvalues, while static const
members are. It also used to be a common workaround for compilers that didn't let you initialize static integral constants in the class definition. This is explained in another question.
它的一种用途是当您进行模板元编程时,因为枚举对象不是左值,而static const
成员是。对于不允许您在类定义中初始化静态整数常量的编译器,它也曾经是一种常见的解决方法。这在另一个问题中有解释。
回答by iammilind
(1) int color = 1;
color
is changeable (accidently).
color
是可变的(偶然)。
(2) enum { color = 1 };
color
cannot be changed.
color
无法更改。
The other option for enum
is,
另一种选择enum
是,
const int color = 1; // 'color' is unmutable
Both enum
and const int
offer exactly same concept; it's a matter of choice. With regards to popular belief that enum
s save space, IMO there is no memory constraint related to that, compiler are smart enough to optimize const int
when needed.
双方enum
并const int
提供完全相同的概念; 这是一个选择问题。关于enum
节省空间的流行信念,IMO 没有与此相关的内存限制,编译器足够聪明,可以const int
在需要时进行优化。
[Note: If someone tries to use const_cast<>
on a const int
; it will result in undefined behavior (which is bad). However, the same is not possible for enum
. So my personal favorite is enum
]
[注意:如果有人试图const_cast<>
在const int
; 它会导致未定义的行为(这是不好的)。但是,对于enum
. 所以我个人最喜欢的是enum
]
回答by atoMerz
When you useenum {color = 1}
you're not using any memory it's like#define color 1
当您使用时,enum {color = 1}
您没有使用任何内存,就像#define color 1
If you declare a variableint color=1
Then you're taking up memory for a value that's not to be changed.
如果你声明了一个变量,int color=1
那么你就会为一个不会改变的值占用内存。
回答by atoMerz
Answer
回答
Readability and performance.
Details are describbed as notes to examples below.
可读性和性能。
详细信息描述为以下示例的注释。
Use cases
用例
Personal example
个人例子
In Unreal Engine 4(C++ game engine), I have following property (engine exposed member variable):
在虚幻引擎 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;
This is a value of floor slope player is standing on (value ∈ [0; 90)°), if any.
Because of engine limitations, it cannot be neither std::optional
nor TOptional
.
I've came up with a solution to add another self explainable variable bIsOnFloor
.
这是玩家站立的地面坡度值(值 ∈ [0; 90)°),如果有的话。
由于引擎限制,它不能不是也不std::optional
是TOptional
。
我想出了一个解决方案来添加另一个自我解释变量bIsOnFloor
。
bool bIsOnFloor = false;
My C++ only internal setter for FloorSlope
takes the following form:
我的 C++ 唯一内部设置器FloorSlope
采用以下形式:
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);
};
Adding special case where FloorSlope
parameter would take argument of -1.f
would be hard to guess and not user friendly.
Instead, I'd rather create False
enum
field:
添加FloorSlope
参数将采用的参数的特殊情况-1.f
将很难猜测并且对用户不友好。相反,我宁愿创建False
enum
字段:
enum { False };
This way, I can simply overload SetFloorSlope
function that takes intuitive False
instead of -1.f
.
这样,我可以简单地重载SetFloorSlope
需要直观False
而不是-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: —";
};
When a player character hits a floor upon applying gravity to it on tick, I simply call:
当玩家角色在滴答时对其施加重力而撞到地板时,我只需调用:
SetFloorSlope(FloorSlope);
… where FloorSlope
is a float
value ∈ [0; 90)°.
Otherwise (if it does not hits a floor), I call:
... 其中FloorSlope
是一个float
值 ∈ [0; 90)°。否则(如果它没有撞到地板),我调用:
SetFloorSlope(False);
This form (as opposed to passing -1.f
) is much more readable, and self explanatory.
这种形式(与传递相反-1.f
)更具可读性,并且不言自明。
Engine example
发动机示例
Another example may be to prevent or force initialization.
Mentioned above Unreal Engine 4 commonly uses FHitResult
struct
containing information about one hit of a trace, such as point of impact and surface normal at that point.
另一个例子可能是阻止或强制初始化。上面提到的虚幻引擎 4 通常使用包含有关轨迹一次命中的信息,例如撞击点和该点的表面法线。FHitResult
struct
This complex struct
calls Init
method by default, setting some values to certain member variables. This can be forced or prevented (public docs: FHitResult
#constructor):
默认情况下,这种复杂的struct
调用Init
方法,为某些成员变量设置一些值。这可以被强制或阻止(公共文档:FHitResult
#constructor):
FHitResult()
{
Init();
}
explicit FHitResult(float InTime)
{
Init();
Time = InTime;
}
explicit FHitResult(EForceInit InInit)
{
Init();
}
explicit FHitResult(ENoInit NoInit)
{
}
Epic Games defines such enum
s similiar, but adds redundant enum
names:
Epic Games 定义了enum
类似的,但添加了多余的enum
名称:
enum EForceInit
{
ForceInit,
ForceInitToZero
};
enum ENoInit {NoInit};
Passing NoInit
to the constructor of FHitResult
prevents initialization, what can lead to performance gain by not initializing values that will be initialized elsewhere.
传递NoInit
给构造函数会FHitResult
阻止初始化,通过不初始化将在其他地方初始化的值来提高性能。
Community example
社区示例
FHitResult(NoInit)
usage in DamirH's poston Comprehensive GameplayAbilities Analysis Series:
FHitResult(NoInit)
DamirH在综合游戏能力分析系列文章中的用法:
//A struct for temporary holding of actors (and transforms) of actors that we hit
//that don't have an ASC. Used for environment impact GameplayCues.
struct FNonAbilityTarget
{
FGameplayTagContainer CueContainer;
TWeakObjectPtr<AActor> TargetActor;
FHitResult TargetHitResult;
bool bHasHitResult;
public:
FNonAbilityTarget()
: CueContainer(FGameplayTagContainer())
, TargetActor(nullptr)
, TargetHitResult(FHitResult(ENoInit::NoInit))
, bHasHitResult(false)
{
}
// (…)
回答by marcinj
I dont see it mentioned, another use is to scope your constants. I currently work on code that was written using Visual Studio 2005, and it is now ported to android - g++. In VS2005 you could have code like this enum MyOpts { OPT1 = 1 };
and use it as MyOpts::OPT1 - and compiler did not complain about it, even though it is not valid. g++ reports such code as error, so one solution is to use anonymous enum as follows: struct MyOpts { enum {OPT1 =1}; };
, and now both compilers are happy.
我没有看到它提到,另一个用途是限定常量的范围。我目前正在处理使用 Visual Studio 2005 编写的代码,现在它已移植到 android - g++。在 VS2005 中,您可以拥有这样的代码enum MyOpts { OPT1 = 1 };
并将其用作 MyOpts::OPT1 - 即使它无效,编译器也不会抱怨它。g++ 将此类代码报告为错误,因此一种解决方案是使用匿名枚举如下:struct MyOpts { enum {OPT1 =1}; };
,现在两个编译器都很高兴。