C++ compile-time enum to string, iteration, in a single header file

Overview

Better Enums   Try online Travis status AppVeyor status

Reflective compile-time enum library with clean syntax, in a single header file, and without dependencies.

Better Enums code overview

In C++11, everything can be used at compile time. You can convert your enums, loop over them, find their max, statically enforce conventions, and pass along the results as template arguments or to constexpr functions. All the reflection is available for your metaprogramming needs.

The interface is the same for C++98 — you just have to use most of it at run time only. This library does provide scoped and sized enums, something not built into C++98.

See the project page for full documentation.


Installation

Simply add enum.h to your project.


Additional features

  • Uses only standard C++, though, for C++98, variadic macro support is required (major compilers have it).
  • Supported and tested on clang, gcc, and msvc.
  • Fast compilation. You have to declare a few dozen enums to slow down your compiler as much as only including iostream does.
  • Use any initializers and sparse ranges, just like with a built-in enum.
  • Control over size and alignment — you choose the representation type.
  • Stream operators.
  • Does not use the heap and can be compiled with exceptions disabled, for use in minimal freestanding environments.

Limitations

  1. The biggest limitation is that the BETTER_ENUM macro can't be used inside a class. This seems difficult to remove. There is a workaround with typedef (or C++11 using):

    BETTER_ENUM(SomePrefix_Color, uint8_t, Red, Green, Blue)
    
    struct triplet {
        typedef SomePrefix_Color    Color;
        Color                       r, g, b;
    };
    
    triplet::Color  color;

    You can, however, use BETTER_ENUM inside a namespace.

  2. The macro has a soft limit of 64 declared constants. You can extend it by following these instructions. Ultimately, the number of constants is limited by your compiler's maximum macro argument count.

  3. In some cases, it is necessary to prefix constants such as Channel::Red with a + to explicitly promote them to type Channel. For example, if you are doing a comparison:

    channel == +Channel::Red
  4. On msvc, you may need to enable warning C4062 to get switch case exhaustiveness checking.


History

The original version of the library was developed by the author in the winter of 2012-2013 at Hudson River Trading, as a replacement for an older generator called BETTER_ENUM.

Comments
  • Added travis.yml

    Added travis.yml

    Your CONTRIBUTING.md states that you are looking for a third-party service to run your tests on. Travis is a continous integration service that builds every commit and even pull requests for you. You can log in using your github account and add your repository. Every time you push a new commit or someone submits a pull request, travis will build the commit and notify you if it failed. You can learn more about travis here.

    This PR adds a .travis.yml so that travis knows how to run your tests. It currently tests clang 3.4 and g++ 4.8. For an example how this might look see https://travis-ci.org/UnrealQuester/better-enums/builds/68665505

    opened by UnrealQuester 28
  • Usage inside a class

    Usage inside a class

    You can do something like this:

    
    
    // Make sure it's possible to compare string correctly
    constexpr bool static_strequal_helper(const char * a, const char * b, unsigned len) {
       return (len == 0) ? true : ((*a == *b) ? static_strequal_helper(a + 1, b + 1, len - 1) : false);
    }
    
    // This is the base class using CRTP for capturing the enum' class type
    // With the macro trick below, it allow auto registration even in classes of your enum, and 
    // also O(1) runtime string lookup-to-value matching
    template <typename T>
    struct CatalogEnum
    {
         typedef T ClassType;
         static std::map<const char *, int> enumToValue; 
         static void registerField(const char * name, int value) { enumToValue[name] = value; }
         static int fromStringImpl(const char * name) { return enumToValue[name]; }
    };
    
    /* This is the basic block. Because your enum derives from CatalogEnum, it has a registerField member, so it can be registered at run time (before any usage)
    Also, I've provided a basic constexpr trick to match against an enum value, but not the code 
    for complete lookup. 
    It should not be difficult to iterate over all the RegisterEnum entries at compile time to perform O(N) lookup for a fromString method. 
    Please notice that even if you enum as same value for 2 field, it'll generate two different instance of this
    template, and will still work correctly, since the pointer to _get_field_name is different */ 
    template <typename Class, int value, typename const char* (*enumName)()>
    struct RegisterEnum
    {
          // Compile-time version
          template<size_t N>
          constexpr bool match_string(const char (&a)[N]) const { return static_strequal_helper(a, (*enumName)(), N); }
          // Run-time version
          bool match_string(const char* a) const { return strcmp(a, (*enumName)()) == 0; }
    
          RegisterEnum() { CatalogEnum<Class>::registerField((*enumName)(), value); }
    };
    
    // Basic macro trick, it declares a static function, and uses its address as a templated differentiator
    // Then the templated object constructor takes care of calling the Catalog::registerField method to register 
    // the enum field
    #define DeclMember(A) \
           static const char *__get##A() { return #A; } \
           RegisterEnum<ClassType, A, &__get##A> __##A;
    
    // And some of your code:
    #define ENUM(Name, type, A, B, C) \
        struct Name : CatalogEnum<Name> { enum Type : type { A, B, C }; \
           DeclMember(A) \
           DeclMember(B) \
           DeclMember(C) \
           static Type fromString(const char * name) { return (Type)fromStringImpl(name); } \
           template <size_t N>
           static constexpr fromString(const char (&a)[N]); // Should iterate through all RegisterEnum  and call match_string(a) on them  
       [your actual code here]
       }; 
    
    
    // Usage:
    struct A
    {
          ENUM(Color, int, Blue, Red, Green); // OMG, it works!
    
         void exampleMethod() { Color::Type c = Color::fromString("RED"); }
    };
    
    opened by X-Ryl669 20
  • Visual Studio 2015 constexpr status

    Visual Studio 2015 constexpr status

    Visual Studio 2015 added support for constexpr, but the implementation seems too buggy to get it working with Better Enums without a bunch of workarounds. Progress is in the branch vs2015-constexpr. Internal compiler errors can be seen here – search for "error" in the log.

    status 
    opened by aantron 14
  • Enum type should be default constructible

    Enum type should be default constructible

    Normal scoped enumerations are default constructible:

    enum class Fubar { One, Two, Three };
    auto myinstance = Fubar{};
    

    However, your ENUM macro does not yield a struct that matches these semantics:

    ENUM(Fubar, int, One, Two, Three);
    auto myinstance = Fubar{}; // compiler error on MSVC12
    

    The error I get is:

    error C2248: 'Fubar' : cannot access private member declared in class 'Fubar'

    These semantics are extremely important for template metaprogramming. Example test case:

    template<typename T>
    void DeserializeEnum(T& enumerator, T const& default_value = T{});
    

    Internally, the method above will attempt to stream in a string and map it to a proper enumerator. If the string does not map to a valid enumerator, it will instead set it to the value of default_value. This template works just fine for true scoped enumerations, but not with your struct declared by the ENUM macro.

    opened by rcdailey 13
  • Increase compiler warning levels and associated code changes

    Increase compiler warning levels and associated code changes

    Thanks for Better Enums. It's incredibly useful.

    Some projects wishing to include enum.h might be following the advice of enabling all available compiler warning flags (eg C++ Coding Standards by Herb Sutter and Andrei Alexandrescu, Item #1, "Compile cleanly at high warning levels"). Such projects currently need to either modify enum.h or use #pragm directives to disable warnings for that file.

    This PR modifies the example and test Makefile to enable all available warning flags, along with associated code changes to comply with the resulting compiler warnings. This allows enum.h to be directly used in projects without editing or #pragma directives. The test cases pass and the examples execute without error.

    opened by benalexau 12
  • Recommend magic_enum?

    Recommend magic_enum?

    See https://github.com/Neargye/magic_enum#readme.

    If someone tries both Better Enums and magic_enum, and there is a reason to prefer Better Enums, please leave a comment here.

    Otherwise, I think we should recommend magic_enum and move Better Enums toward deprecation.

    cc @Neargye

    opened by aantron 11
  • Are there guarantees on size with better enums?

    Are there guarantees on size with better enums?

    I'm in a weird situation where, because of std::vector<bool> bit packing and a need to interface with a C API I need to make my own boolean type (the other alternative being using a non-standard container, like boost::container::vector).

    Because of that C API I need a guarantee that sizeof(BETTER_ENUM(foo, char)) == sizeof(char), does Better Enums provide such a guarantee?

    Using a simple test code (below) this seems to be true, but the actual implementation is somewhere so deep among the macros it's difficult to analyze.

    Test code:

    #include <iostream>
    
    #include <better-enums/enum.h>
    
    BETTER_ENUM(mbool, char, mfalse = 0, mtrue = 1)
    
    int main() {
        std::cout << sizeof(mbool) << ' ' << sizeof(char) << std::endl;
        std::cout << std::boolalpha << (sizeof(mbool) == sizeof(char)) << std::endl;
    
        return 0;
    }
    

    Edit: I'm aware that enum class mbool : char would work for this use case, but Better Enums are, well, better.

    opened by jaskij 10
  • constexpr not working in Visual Studio 2017?

    constexpr not working in Visual Studio 2017?

    Hello @aantron & co.,

    Trying to compile with BETTER_ENUM in Visual Studio 2017 produces the following error:

    E0028 expression must have a constant value attempt to access run-time storage

    The error occurs at the assignment of _value_array.

    Here are a few test cases of the compiler behavior:

        //These compile
        constexpr const int example0[] = {
          123
        };
        constexpr const MyEnum example1[] = {
          MyEnum::MyEnumValue
        };
        constexpr const int myEnumValue = MyEnum::MyEnumValue;
        constexpr const int example2[] = {
          myEnumValue
        };    
    
        //These array assignments all produce error E0028
        constexpr const MyEnum example3[] = {
          ((::better_enums::_eat_assign<MyEnum>)MyEnum::MyEnumValue = 0)
        };
        constexpr const MyEnum example4[] = {
          ::better_enums::_eat_assign<MyEnum>(MyEnum::MyEnumValue)
        };
        constexpr ::better_enums::_eat_assign<MyEnum> myEat(MyEnum::MyEnumValue);
        constexpr const MyEnum example5[] = {
          myEat
        };
    

    This is in Visual Studio 2017 (v15.4.5), and happens using any of the ISO C++14, ISO C++17, and Latest Draft compilers.

    I know this is intended to work (apropos the recent commit to support constexpr in VS2017). What's likely to be the issue?

    ❤️ , dan

    opened by dgant 10
  • Support using better-enum as key in dictionaries and maps.

    Support using better-enum as key in dictionaries and maps.

    Thanks for better-enum. It is awesome. However I was missing a feature to use the enum values in unordered_map. I have extended it for this use case. Please review and accept my PR.

    int main()
    {
    	Channel channel = Channel::Red;
    	
    	std::unordered_map<Channel, int> u = {
    		{Channel::Red, 1},
    		{Channel::Blue, 3},
    	};
    
    	printf("Red %d\n", u[Channel::Red]);
    	printf("Blue %d\n", u[Channel::Blue]);
    
    	return 0;
    }
    
    opened by svnscha 9
  • Fix name resolution errors

    Fix name resolution errors

    1. Global stream I/O operators were sometimes not found in my code. I didn't have enough patience to detect the exact cause of this and to reproduce the error using a small example, but this is apparently due to some complex ADL rules. I moved the operators to the enum namespace scope as I think it's more appropriate, the lookup is more reliable now. It also allowed to get rid of the hacky "traits" class.
    2. Using better_enums as a name for both global and nested namespaces is pretty error-prone as the nested one will be chosen by default, unless ::better_enums is specified explicitly. I concatenated the nested namespace names to produce a unique one and prevent the name clash.
    opened by cheparukhin 9
  • Appveyor and Travis badge

    Appveyor and Travis badge

    Now that we have ci, you might want to add the travis status image and the appveyor status badge. This way users can immediately see that you project has automated tests and feel a little more comfortable in using it. And potential contributors can be confident that their contributions are automatically tested.

    opened by UnrealQuester 9
  • Add equality operators to compare Enum with enumerated value

    Add equality operators to compare Enum with enumerated value

    The aim of this PR is to add the possibility to compare enums with values without the need to add + to explicitly promote them to types.

    For example the following code is possible:

    Channel red = Channel::Red;
    
    if (red != Channel::Blue) {
    }
    if (red == Channel::Red) {
    }
    if (Channel::_from_string("Red) != Channel::Red) {
    }
    

    See unit tests for examples.

    opened by gamante91 1
  • Cannot use better_enum from class

    Cannot use better_enum from class

    I would like to declare a better_enum from inside a class. For example,

    #include <enum.h>
    class A
    {
      public:
        BETTER_ENUM(Word, int, Hello, World)
        A(Word x){}
    };
    
    int main()
    {
      A x(Word::Hello);
      return 0;
    }
    

    Unfortunately, this fails to compile. However, if I move the BETTER_ENUM declaration outside of the class, this works just fine. Is there another way to declare a better_enum inside a C++ class?

    opened by gri6507 1
  • Need to have standard Debian packaging capability

    Need to have standard Debian packaging capability

    This git repo is very useful. However, it currently does not have a means to create a Debian package. I've created a new PullRequest to provide that capability.

    opened by gri6507 0
  • Provided Debian Packaging files

    Provided Debian Packaging files

    PROBLEM STATEMENT: Better-enums currently does not provide a way to deliver its contents as a Debian package

    SOLUTION: Added Debian packaging files

    DETAILS: Follows the standard Debian Packaging rules. See https://www.debian.org/doc/manuals/debmake-doc/index.en.html

    IMPACT ANALYSIS: When making future releases, debian/changelog needs to be updated

    TESTING:

    • Ran dpkg-buildpackage -us -uc -b
    • Ran dpkc -c on resulting DEB file
    • Ran lintian on resulting DEB file
    • Installed resulting DEB file and compiled against it using pkg-config --cflags better-enums
    opened by gri6507 3
  • How to reflect to enum with type and value strings?

    How to reflect to enum with type and value strings?

    Hi, this is a great work you’v made. But how to reflect from strings of enum value and name?

    I have,

    enum Type
    {
       A = 1,
       B = 2
    };
    

    and text content

    enum name : Type ; value: A

    How to reflect the strings into Type with A?

    I know there is no reflection in c++, but can we build that system just with help of this better-enum project?

    opened by WorstCodeWay 4
  • Compile-time name trimming and binary size

    Compile-time name trimming and binary size

    I've added better-enums to an embedded project with limited binary size. After converting a single existing enum to BETTER_ENUM the binary size increased by ~5 kB which is not acceptable for such a project. I was able to trim this to less than 1 kB by enabling the compile-time name trimming feature so it seems that the runtime code is pulling in many dependencies or generating much code.

    In such a case using the compile-time name trimming feature is definitely preferred, so I suggest to add a small note about that to the documentation for other users.

    opened by Christian-Sander 0
Releases(0.11.3)
  • 0.11.3(Oct 19, 2020)

    Additions

    Bugs fixed

    • -Wold-style-cast on Clang (#74, Felipe Lema).
    • Don't trigger compiler bug with -Wattributes on GCC ≥ 7 (#79, CJ Smith).
    • Missing BETTER_ENUMS_IGNORE_ATTRIBUTES_* definitions on Clang (#81, Jan-Gerd Tenberge).
    Source code(tar.gz)
    Source code(zip)
  • 0.11.2(Apr 2, 2019)

    Additions

    • Enable constexpr support on clang-cl (#26, Zsolt Parragi).
    • Enable constexpr support on VS 2017 (#47, Zsolt Parragi).
    • _to_index, _from_index, and related functions (#59, Piotr Kosek).
    • Specialize maps for descriptions of type wchar_t* (#44, @codercheny).

    Bugs fixed

    • Move stream I/O operators out of the global namespace (#22, Alex Cheparukhin).
    • Internal namespaces used by Better Enums cause name clashes (#22, Alex Cheparukhin).
    • Unused function warnings on comparison operators (#27, Alex Cheparukhin).
    • Unused variables with names cause warnings on MSVC (#41, Anuradha Dissanayake).
    • VS 2015 warns when not using enum class (#41, Anuradha Dissanayake).
    • Docs: note strongly that warning C4062 has to be enabled on MSVC for exhaustiveness checking (#49).
    • Identifiers that begin with an underscore followed by a capital letter are reserved (#61, Felix Dombek).
    • Internal values array initialization not accepted as constexpr by VS 2017 (#53, @D4koon).

    Miscellaneous

    • Syntax-highlight the code in the README (#67, Wojciech Bartnik).
    • Remove tabs that have crept into enum.h (#72, @Xeverous).
    Source code(tar.gz)
    Source code(zip)
  • 0.11.1(Mar 14, 2016)

    • Removed double underscores in internal names (by Mikhail Ovchinnikov).
    • Fixed some warnings (some by Mitsutaka Takeda).
    • Various build, testing, and documentation fixes.
    Source code(tar.gz)
    Source code(zip)
Nameof operator for modern C++, simply obtain the name of a variable, type, function, macro, and enum

_ _ __ _____ | \ | | / _| / ____|_ _ | \| | __ _ _ __ ___ ___ ___ | |_ | | _| |

Daniil Goncharov 1.5k Jan 4, 2023
A modern compile-time reflection library for C++ with support for overloads, templates, attributes and proxies

refl-cpp v0.12.1 Documentation refl-cpp encodes type metadata in the type system to allow compile-time reflection via constexpr and template metaprogr

Veselin Karaganev 783 Dec 31, 2022
A compiling time static reflection framework for C++

static_reflect This is a fully compiling time static reflection lightweight framework for C++. It provides a very rich compile-time reflection functio

null 13 Dec 25, 2022
Header-only, non-intrusive and macro-free runtime reflection system in C++

Header-only runtime reflection system in C++ The reflection system was born within EnTT and is developed and enriched there. This project is designed

Michele Caini 452 Jan 4, 2023
A compile-time enabled Modern C++ library that provides compile-time dimensional analysis and unit/quantity manipulation.

mp-units - A Units Library for C++ The mp-units library is the subject of ISO standardization for C++23/26. More on this can be found in ISO C++ paper

Mateusz Pusz 679 Dec 29, 2022
header-only UTF-8 string functions based on STL-string

utf8_xxx header-only UTF-8 string functions based on STL-string size_t utf8_len(const std::string& _Str) std::string utf8_sub(const std::string& _Str,

Voidmatrix 2 Dec 27, 2021
StrCrypt Compile-time string crypter library for C++

StrCrypt Compile-time string crypter library for C++ Having plain strings stored in the binary file or in memory can help reversering attempts to be m

null 58 Jun 26, 2022
C++20 compile time compressed string tables

Squeeze - C++20 Compile time string compression Experiments in building complex compile time executed code using constexpr functions to generate a com

Ashley Roll 43 Dec 7, 2022
Compile-time String to Byte Array

STB Compile-time String to Byte Array. Why? You may ask, why'd you want to do this? Well, this is a common issue in the cheat development scene, where

cristei 11 Jan 3, 2023
Pipet - c++ library for building lightweight processing pipeline at compile-time for string obfuscation, aes ciphering or whatever you want

Pipet Pipet is a lightweight c++17 headers-only library than can be used to build simple processing pipelines at compile time. Features Compile-time p

C. G. 60 Dec 12, 2022
C string library based on string ends

C string library based on string ends

Leah Neukirchen 18 Jun 8, 2022
LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.

LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values. Authors: Sanjay Ghem

Google 31.6k Jan 7, 2023
C++ functions matching the interface and behavior of python string methods with std::string

Pystring is a collection of C++ functions which match the interface and behavior of python's string class methods using std::string. Implemented in C+

Sony Pictures Imageworks 764 Jan 4, 2023
C Program to input a string and adjust memory allocation according to the length of the string.

C-String C Program to input a string and adjust memory allocation according to the length of the string. With the help of this program, we have replic

Kunal Kumar Sahoo 1 Jan 20, 2022
📚 single header utf8 string functions for C and C++

?? utf8.h A simple one header solution to supporting utf8 strings in C and C++. Functions provided from the C header string.h but with a utf8* prefix

Neil Henning 1.3k Dec 28, 2022
A single file, single function, header to make notifications on the PS4 easier

Notifi Synopsis Adds a single function notifi(). It functions like printf however the first arg is the image to use (NULL and any invalid input should

Al Azif 9 Oct 4, 2022
json2cpp is compiles a json file into static constexpr data structures that can be used at compile time or runtime

json2cpp json2cpp is compiles a json file into static constexpr data structures that can be used at compile time or runtime. Features Literally 0 runt

Jason Turner 180 Dec 22, 2022