{"id":13730519,"url":"https://github.com/quicknir/wise_enum","last_synced_at":"2025-05-08T03:30:49.902Z","repository":{"id":46372007,"uuid":"98955314","full_name":"quicknir/wise_enum","owner":"quicknir","description":"A reflective enum implementation for C++","archived":false,"fork":false,"pushed_at":"2024-02-08T22:03:17.000Z","size":136,"stargazers_count":291,"open_issues_count":13,"forks_count":27,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-06T12:17:10.608Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quicknir.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-01T03:28:30.000Z","updated_at":"2025-04-15T17:38:55.000Z","dependencies_parsed_at":"2024-11-14T21:32:16.387Z","dependency_job_id":"ba15ede3-6745-4a8a-8b8f-89afb8f56f85","html_url":"https://github.com/quicknir/wise_enum","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicknir%2Fwise_enum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicknir%2Fwise_enum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicknir%2Fwise_enum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quicknir%2Fwise_enum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quicknir","download_url":"https://codeload.github.com/quicknir/wise_enum/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252992891,"owners_count":21837188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T02:01:16.019Z","updated_at":"2025-05-08T03:30:49.589Z","avatar_url":"https://github.com/quicknir.png","language":"C","readme":"# wise_enum [![Build Status](https://travis-ci.com/quicknir/wise_enum.svg?branch=master)](https://travis-ci.com/quicknir/wise_enum) [![Build status](https://ci.appveyor.com/api/projects/status/h91ay4xrbsdrq6gk/branch/master?svg=true)](https://ci.appveyor.com/project/quicknir/wise-enum/branch/master)\n\n\n\u003e Because reflection makes you wise, not smart\n\n`wise_enum` is a standalone smart enum library for C++11/14/17. It supports\nall of the standard functionality that you would expect from a smart enum class\nin C++:\n - Tells you the number of enumerators\n - Lets you iterate over all enum values\n - Converts string to enum, and enum to string\n - Does everything in an idiomatic C++ way (friendly to generic programming,\n   compile time programming, etc)\n\n### Examples\n\nLet's look at a bit of code. You can declare an enum like this:\n\n```cpp\n// Equivalent to enum Color {GREEN = 2, RED};\nWISE_ENUM(Color, (GREEN, 2), RED)\n```\n\nYou can also declare an enum class instead of an enum, specify the storage\nexplicitly, declare an enum nested inside a class, or even adapt an already\ndeclared enum:\n\n```cpp\n// Equivalent to enum class MoreColor : int64_t {BLUE, BLACK = 1};\nWISE_ENUM_CLASS((MoreColor, int64_t), BLUE, (BLACK, 1))\n\n// Inside a class, must use a different macro, but still works\nstruct Bar {\n    WISE_ENUM_MEMBER(Foo, BUZ)\n};\n\n// Adapt an existing enum you don't control so it works with generic code\nnamespace another_lib {\nenum class SomebodyElse { FIRST, SECOND };\n}\nWISE_ENUM_ADAPT(another_lib::SomebodyElse, FIRST, SECOND)\n```\n\nYou can ask the enum how many enumerators it has:\n\n```cpp\nstatic_assert(wise_enum::size\u003cColor\u003e == 2, \"\");\n```\n\nIterate over the enumerators:\n\n```cpp\nstd::cerr \u003c\u003c \"Enum values and names:\\n\";\nfor (auto e : wise_enum::range\u003cColor\u003e) {\n  std::cerr \u003c\u003c static_cast\u003cint\u003e(e.value) \u003c\u003c \" \" \u003c\u003c e.name \u003c\u003c \"\\n\";\n}\n```\n\nConvert between strings and enums:\n\n```cpp\n// Convert any enum to a string\nstd::cerr \u003c\u003c wise_enum::to_string(Color::RED) \u003c\u003c \"\\n\";\n\n// Convert any string to an optional\u003cenum\u003e\nauto x1 = wise_enum::from_string\u003cColor\u003e(\"GREEN\");\nauto x2 = wise_enum::from_string\u003cColor\u003e(\"Greeeeeeen\");\n\nassert(x1.value() == Color::GREEN);\nassert(!x2);\n```\n\nCheck whether something is a wise enum at compile time:\n```cpp\nstatic_assert(wise_enum::is_wise_enum_v\u003cColor\u003e, \"\");\nstatic_assert(!wise_enum::is_wise_enum_v\u003cint\u003e, \"\");\nenum flub { blub, glub };\nstatic_assert(!wise_enum::is_wise_enum_v\u003cflub\u003e, \"\");\n```\n\n### Design\n\nIt has a few notable design choices.\n\nFirst, when you use one of the macros to declare your enum, what gets declared\n(among other things) is exactly the vanilla enum (or enum class) that you would\nexpect. Not an enum like class, or anything like that. That means that\n`wise_enum`s can be used exactly like regular enums in non-reflective contexts,\nbecause they are regular enums. They can be used as non-type template\nparameters, and they can be used in switch case statements, unlike any user\ndefined type. This also means that upgrading a regular enum already widely used\n(non-reflectively) in your codebase to a wise enum is never a breaking change.\nNo strange behavior, or edge cases, when used with other third party libraries\n(e.g. serialization), or standard library type traits.\n\nSecond, all the functionality in defining enums is preserved. You can define\n`enum` or `enum class`es, set storage explicitly or let it be implicit, define\nthe value for an enumeration, or allow it to be determined implicitly. You can\nalso define enums nested in classes, which isn't supported in some smart enum\nlibraries.\n\nThird, it's quite compile-time programming friendly. Everything is `constexpr`,\nand a type trait is provided. This makes it easy to handle wise enums in a\nspecific way in generic code. For example, if you have a logger, it can't\nintelligently log a vanilla enum without more information, but it can log a wise\nenum, so you can use the type trait to handle them differently (with no\nperformance cost of course).\n\nFourth, it's careful with regards to performance and generated assembly. It\nmakes zero heap allocations and does zero dynamic initialization, and does not\nuse exceptions. The enum -\u003e string is an optimal switch-case. String -\u003e enum is\ncurrently a linear search; this may be changed in the future (most alternatives\nare not trivial to implement without doing heap allocations or dynamic\ninitialization).\n\n### Quick Comparison of Alternatives\n\nThe best known alternative is probably [Better\nEnums](https://github.com/aantron/better-enums). The biggest issue with Better\nEnums is simply that its macros don't actually create enums or enum classes, but\nenum like classes. This carries all of the disadvantages discussed in the\nprevious section, and for me was just a deal breaker. There are also more minor\nissues like not being able to define a nested enum, having a lower default\nenumeration limit. Conversely, I'm not aware of any advantages, except one: it\ndoes support C++03, which wise enum never will, so it's a good choice for older\ncodebases.\n\nA recent interesting alternative is [Meta\nEnum](https://github.com/therocode/meta_enum). This does declare actual\nenum/enum classes. As benefits, it doesn't have any limit on the number of\nenumerations by design, and it doesn't require different macros for declaring\nenums nested inside classes. As far as I can tell though, the approach means\nthat it can't support switch case generation (e.g. for to_string), nor can it\nsupport 11. It currently only seems to support 17 but 14 support may be\npossible.\n\nAs far as I saw, neither library has something like the adapt macro, though I\nthink either one could add it pretty easily. There are other implementations,\nbut most of the ones I've seen are very clearly very short projects, lacking\nsupport for basic features (e.g. controlling enum values) and documentation.\n\nOverall, I feel like wise enum is the best choice for an enum library for a\ntypical, modern C++ codebase.\n\nIf any of this information is incorrect, please let me know and I'll make\ncorrecting it the highest priority.\n\n### Version differences\n\nWise enum tries to target each language version idiomatically. In 11, template\nvariables, which are the recommended interface in 14/17 are not available so using\nthe typical class template static interface instead is necessary. Many functions lose\n`constexpr` in 11. The difference between 14 and 17 is mostly in the types used,\ndiscussed in the next section.\n\n### Types and Customizations\n\nThere are two types that you can customize in wise_enum, by defining macros: the\noptional type, and the string type.\n\n| Type          | 11/14 default       | 17 default       | customize macro       | type alias |\n| ------------- | ----------------- | ----------      | ---------------      | --- |\n| optional      | `wise_enum::optional` | `std::optional`    | `WISE_ENUM_OPTIONAL_TYPE`    | `wise_enum::optional_type\u003cT\u003e` |\n| string        | `const char *`        | `std::string_view` | `WISE_ENUM_STRING_TYPE` | `wise_enum::string_type` |\n\nIf you only support 17, the defaults should be fine. If you're on 11/14, the\ndefaults are fine as well, but if you want to be forward compatible I'd consider\nrounding up a string_view implementation somewhere and using that. Otherwise,\nsince `const char*` and `string_view` don't have the same interface, you may\nhave breakages when upgrading. Finally, if you're supporting both 11/14 and 17 I'd\ndefinitely define both macros so the same type is used in your builds.\n\nYou can define the macro either in your build system, or by having a stub header\nthat defines them and then includes `wise_enum.h`, and only including via the\nstub.\n\nYou can also customize the use of exceptions. If you use the CMake option\n`NO_EXCEPTIONS` or otherwise define the macro `WISE_ENUM_NO_EXCEPT`, then\nwise_enum should be fully compatible with `-fno-exceptions`. The API never\ndirectly throws exceptions anyhow; the only change in behavior is that the\nprovided `optional` (and `compact_optional`) will abort rather than throw on\n`value()` calls if the optional is empty, similar to the behavior of most (all?)\nstandard library optional implementations when exceptions are disabled.\n\n### Extra Features\n\nOver time I'd like to leverage some of the capabilities of wise enum to do other useful enum related things.\n\n#### Compact optional\n\nI have a compact optional implementation included now in wise enum. The key point is that it uses compile time reflection to statically verified that the sentinel value used to indicate the absence of an enum, is not a value used for any of the enumerators. If you add an enumerator to an enum used in a compact optional, and the value of the enum is the sentinel, you get a compilation error.\n\n#### Switch case \"lifts\"\n\nOne problem where C++ gives you little recourse is when you have a runtime value that\nyou want to lift into a compile time value. Consider the following:\n\n```cpp\ntemplate \u003cMyEnum E\u003e\nclass MyDerived : MyInterface {...};\n\nunique_ptr\u003cMyInterface\u003e make(MyEnum e);\n```\n\nIt's hard to write `make` without boilerplate in the general case. You need to manually\nswitch case over all enumerator values, and in each case put the compile time constant\ninto the template. Wise enum will shortly (exact interface being worked out) provide\na facility that takes an enum and a lambda, does the switch case over all values\ninternally, and calls the lambda making the enum available as a compile time constant.\n\nComing soon!\n\n#### Enum Sets\nPlanned for the future.\n\n### Limitations\n\nThere are some known limitations:\n\n - If there are enumerators with the same value, then `to_string` will not work.\n   You can declare the enum and use all the other API. This is both because it\n   doesn't jive at all with the implementation, and even conceptually it's not\n   clear how you would handle a conversion to string since multiple strings\n   would be associated with the same value.\n - By default, you are limited to 256 enumerations. If you need more, simply run\n   the `create_generated` script to create a file with as many as you need, and\n   replace `wise_enum_generated` with that file. The default limit may be raised\n   or lowered based on feedback. An alternative solution here would be to create\n   headers in advance that raise this number, but leave the onus on the user to\n   include them (so users who don't need a large number aren't slowed down)\n\n### Q\u0026A\n\n##### Why didn't I use `BOOST_PP`?\nI started with it, but the limit on sequences was very disappointing (64) and\nthere didn't seem to be any easy way to change it. So then I started down the\ncodegen route, and once there, I wasn't using very much. I know there are always\npeople who prefer to avoid the dependency, so I decided to drop it.\n","funding_links":[],"categories":["C++","Libraries"],"sub_categories":["Misc"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquicknir%2Fwise_enum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquicknir%2Fwise_enum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquicknir%2Fwise_enum/lists"}