The usage of anonymous enums

C++Enums

C++ Problem Overview


What is the purpose of anonymous enum declarations such as:

enum { color = 1 };

Why not just declare int color = 1?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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 want people to be able to take the address of color you might as well prevent it.

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.


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 might prefer to use an enum.

Solution 3 - C++

If this is old code, then enum might have been used for the "enum hack".

You can learn more about the "enum hack", for example, in this link: [enum hack][1]

[1]: http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_023.html "enum hack"

Solution 4 - C++

(1) int color = 1;

color is changeable (accidently).

(2) enum { color = 1 };

color cannot be changed.

The other option for enum is,

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 enums save space, IMO there is no memory constraint related to that, compiler are smart enough to optimize const int when needed.

[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]

Solution 5 - C++

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.

Solution 6 - C++

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):

/// 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.

bool  bIsOnFloor = false;

My C++ only internal setter for FloorSlope takes the following form:

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:

enum { False };

This way, I can simply overload SetFloorSlope function that takes intuitive False instead of -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:

SetFloorSlope(False);

This form (as opposed to passing -1.f) is much more readable, and self explanatory.

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.

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):

FHitResult()
{
	Init();
}

explicit FHitResult(float InTime)
{
	Init();
	Time = InTime;
}

explicit FHitResult(EForceInit InInit)
{
	Init();
}

explicit FHitResult(ENoInit NoInit)
{
}

Epic Games defines such enums similiar, but adds redundant enum names:

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.

Community example

FHitResult(NoInit) usage in DamirH's post on Comprehensive GameplayAbilities Analysis Series:

//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)
    {
    }

// (…)

Solution 7 - C++

When you use
enum {color = 1}
you're not using any memory it's like
#define color 1

If you declare a variable
int color=1 Then you're taking up memory for a value that's not to be changed.

Solution 8 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser707549View Question on Stackoverflow
Solution 1 - C++sharptoothView Answer on Stackoverflow
Solution 2 - C++MottiView Answer on Stackoverflow
Solution 3 - C++Eran Zimmerman GonenView Answer on Stackoverflow
Solution 4 - C++iammilindView Answer on Stackoverflow
Solution 5 - C++R. Martinho FernandesView Answer on Stackoverflow
Solution 6 - C++user1180790View Answer on Stackoverflow
Solution 7 - C++atoMerzView Answer on Stackoverflow
Solution 8 - C++marcinjView Answer on Stackoverflow