DEV Community

Pierre Gradot for Younup

Posted on • Edited on • Originally published at younup.fr

Magic Enum : la révolution des énumérations en C++

Aujourd'hui, il faut que je vous parle d'une bibliothèque qui a vraiment changé ma vie de développeur C++ au cours de la dernière année : Magic Enum. Elle est la création de Daniil Goncharov et est disponible sur Github sous licence MIT.

C'est une "header-only C++17 library" qui permet de faire la réflexion statique sur des enums.

Un bon exemple vaut mieux qu'un long discours :

#include <iostream> #include "magic_enum.hpp"  enum class MyEnum { HELLO = 42, WORLD = 99 }; int main() { constexpr auto enumName = magic_enum::enum_type_name<MyEnum>(); constexpr auto scoped = magic_enum::is_scoped_enum<MyEnum>::value; std::cout << enumName << " is scoped = " << std::boolalpha << scoped << '\n'; constexpr auto count = magic_enum::enum_count<MyEnum>(); std::cout << "It has " << count << " possible values :" << '\n'; for (auto name : magic_enum::enum_names<MyEnum>()) { std::cout << "- " << name << '\n'; } std::cout << '\n'; for (unsigned int i = 0; i < count; ++i) { auto value = magic_enum::enum_value<MyEnum>(i); using namespace magic_enum::ostream_operators; // to pretty print the enum value std::cout << "Value = " << value << '\n'; std::cout << "Integer = " << magic_enum::enum_integer(value) << '\n'; std::cout << "Offset = " << magic_enum::enum_index(value).value() << '\n'; auto name = magic_enum::enum_name(value); std::cout << "Name = " << name << '\n'; std::cout << "---------" << '\n'; } std::cout << '\n'; std::cout << "Cast to enum:" << '\n'; using namespace magic_enum::ostream_operators; // to print std::optional<MyEnum> constexpr auto invalid = magic_enum::enum_cast<MyEnum>(0); constexpr auto HELLO = magic_enum::enum_cast<MyEnum>("HELLO"); constexpr auto hello = magic_enum::enum_cast<MyEnum>("hello"); constexpr auto WORLD = magic_enum::enum_cast<MyEnum>("WORLD"); constexpr auto WORLD_AGAIN = magic_enum::enum_cast<MyEnum>(99); std::cout << invalid << '\n'; std::cout << HELLO << '\n'; std::cout << hello << '\n'; std::cout << WORLD << '\n'; } 
Enter fullscreen mode Exit fullscreen mode

Sortie :

MyEnum is scoped = true It has 2 possible values : - HELLO - WORLD Value = HELLO Integer = 42 Offset = 0 Name = HELLO --------- Value = WORLD Integer = 99 Offset = 1 Name = WORLD --------- Cast to enum: HELLO WORLD WORLD 
Enter fullscreen mode Exit fullscreen mode

J'ai essayé de mettre autant que constexpr pour vous montrer qu'une bonne partie est faisable à la compilation, ce qui veut dire un coût nul à l'exécution. Comme j'ai une boucle, je ne peux pas mettre des constexpr partout mais si je choisis de prendre une valeur particulière de l'énumération, c'est possible :

int main() { using namespace magic_enum::ostream_operators; constexpr auto value = magic_enum::enum_cast<MyEnum>("HELLO").value(); constexpr auto integer = magic_enum::enum_integer(value); constexpr auto index = magic_enum::enum_index(value).value(); constexpr auto name = magic_enum::enum_name(value); std::cout << "Value = " << value << '\n'; std::cout << "Integer = " << integer << '\n'; std::cout << "Offset = " << index << '\n'; std::cout << "Name = " << name << '\n'; } 
Enter fullscreen mode Exit fullscreen mode

Sortie :

Value = HELLO Integer = 42 Offset = 0 Name = HELLO 
Enter fullscreen mode Exit fullscreen mode

Un monde de trucs cools s'ouvre à nous :

  • Fini les gens qui rajoutent une dernière valeur COUNT à l'énumération : à la place, il suffit d'utiliser enum_count().
  • Bonjour les affichages lisibles de valeurs avec "HELLO" à la place de "0" grâce à enum_name() ou l'opérateur de stream fourni.
  • A nous la lecture des chaines pour les transformer en valeur de l'union avec enum_cast().
  • Coucou la réponse facile à "cet entier est-il dans mon énumération ?" avec enum_cast().
  • Enfin la possibilité de donner des valeurs numériques arbitraires aux valeurs de l'énumération tout en les utilisant comme index de tableaux grâce a enum_index().

Si votre compilateur est compatible C++17, téléchargez, utilisez, appréciez. Sinon... il est temps de faire du lobbying pour mettre à jour votre compilateur 😅

Top comments (0)