Quel est le but de l'anonymat enum
des déclarations telles que :
enum { color = 1 };
Pourquoi ne pas simplement déclarer int color = 1
?
Quel est le but de l'anonymat enum
des déclarations telles que :
enum { color = 1 };
Pourquoi ne pas simplement déclarer int color = 1
?
Lisibilité et performance.
<sup>Les détails sont décrits dans les notes aux exemples ci-dessous.</sup>
Sur Unreal Engine 4 (moteur de jeu C++), j'ai la propriété suivante (variable membre exposée du moteur) :
/// Floor Slope.
UPROPERTY
(
Category = "Movement",
VisibleInstanceOnly,
BlueprintGetter = "BP_GetFloorSlope",
BlueprintReadOnly,
meta =
(
ConsoleVariable = "Movement.FloorSlope",
DisplayName = "Floor Slope",
ExposeOnSpawn = true,
NoAutoLoad
)
)
float FloorSlope = -1.f;
Il s'agit d'une valeur de la pente du sol sur laquelle le joueur se trouve (valeur ∈ [0 ; 90)°), le cas échéant.
En raison des limitations du moteur, il ne peut être ni std::optional
ni TOptional
.
J'ai trouvé une solution pour ajouter une autre variable auto-explicative. bIsOnFloor
.
bool bIsOnFloor = false;
Mon seul setter interne C++ pour FloorSlope
prend la forme suivante :
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);
};
Ajoutant le cas particulier où FloorSlope
prendrait l'argument de -1.f
serait difficile à deviner et peu convivial. À la place, je préfère créer False
enum
champ :
enum { False };
De cette façon, je peux simplement surcharger SetFloorSlope
fonction qui prend intuitivement False
au lieu de -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: —";
};
Quand un personnage joueur frappe un sol en appliquant la gravité sur celui-ci, j'appelle simplement :
SetFloorSlope(FloorSlope);
où FloorSlope
est un float
valeur ∈ [0 ; 90)°. Sinon (s'il ne frappe pas un plancher), j'appelle :
SetFloorSlope(False);
Cette forme (par opposition au passage -1.f
) est beaucoup plus lisible et explicite.
Un autre exemple peut être d'empêcher ou de forcer l'initialisation. Mentionné ci-dessus, Unreal Engine 4 utilise couramment FHitResult
struct
contenant des informations sur un impact d'une trace, comme le point d'impact et la normale de la surface à ce point.
Ce complexe struct
appelle Init
par défaut, en fixant certaines valeurs à certaines variables membres. Ceci peut être forcé ou empêché (docs publics : FHitResult
#constructeur ) :
FHitResult()
{
Init();
}
explicit FHitResult(float InTime)
{
Init();
Time = InTime;
}
explicit FHitResult(EForceInit InInit)
{
Init();
}
explicit FHitResult(ENoInit NoInit)
{
}
Epic Games définit ainsi enum
est similaire, mais ajoute une redondance enum
des noms :
enum EForceInit
{
ForceInit,
ForceInitToZero
};
enum ENoInit {NoInit};
Passing NoInit
au constructeur de FHitResult
empêche l'initialisation, ce qui peut conduire à un gain de performance en n'initialisant pas des valeurs qui seront initialisées ailleurs.
FHitResult(NoInit)
l'utilisation dans l'article de DamirH poste sur Série d'analyses complètes du gameplay et des capacités :
//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)
{
}
// (…)
Je ne l'ai pas vu mentionné, mais une autre utilisation est d'étendre vos constantes. Je travaille actuellement sur du code qui a été écrit avec Visual Studio 2005, et qui est maintenant porté sur Android - g++. Dans VS2005, vous pouviez avoir un code comme celui-ci enum MyOpts { OPT1 = 1 };
et l'utiliser comme MyOpts::OPT1 - et le compilateur ne s'en est pas plaint, même s'il n'est pas valide. g++ rapporte un tel code comme une erreur, donc une solution est d'utiliser un enum anonyme comme suit : struct MyOpts { enum {OPT1 =1}; };
et maintenant les deux compilateurs sont heureux.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.