Giter Site home page Giter Site logo

aantron / better-enums Goto Github PK

View Code? Open in Web Editor NEW
1.6K 55.0 167.0 592 KB

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

Home Page: http://aantron.github.io/better-enums

License: BSD 2-Clause "Simplified" License

C++ 87.87% Makefile 3.52% Python 4.09% CMake 4.35% C 0.16%
enum cpp reflection header-only

better-enums's Introduction

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.

better-enums's People

Contributors

aantron avatar benalexau avatar cheparukhin avatar cjsmith-0141 avatar d4koon avatar dutow avatar falconne avatar felipelema avatar felixdombek avatar hazeycode avatar janten avatar michaelernst avatar shelim avatar svnscha avatar unrealquester avatar xeverous avatar yisonpylkita avatar zafirus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

better-enums's Issues

Enable more warnings for testing

Including -Weverything from #15 and the GCC warnings from #1. This is currently prevented by CxxTest triggering many of these warnings, so that needs to be addressed.

Usage to handle measurement units with '/' character

I see Better Enums is a nice project and I'd like using it to define a set of measurement units.
The problem is that some of them (m/s, km/h, ...) contain a '/' character in their string representation.

Is there a way to handle this in Better Enum?

Reasoning behind using the '_' character as a prefix for Better Enum functions

Why is Better Enums using the underscore character '_' as a prefix for all functions? It is forbid in the global namespace by the C++ standard only and I think Better Enums only uses this in the better_enum namespace, so it should be no problem. Nonetheless I ask myself what the intention behind that naming convention is.

Isn't Channel::from_string("Blue") more readable than Channel::_from_string("Blue")?

  • MSDN:

    The first character of an identifier must be an alphabetic character, either uppercase or lowercase, or an underscore ( _ ). Because C++ identifiers are case sensitive, fileName is different from FileName.

Additional resource: https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier

Does this support converting strings to the appropriate enum?

Currently, I'm using better enums for the enums I need to be able to iterate over. It works excellent for that. The only issue is I'm using a separate enum for converting cstrings to enums with rt_crc32.

I noticed there is _from_string_nocase(), which works except I used underscores between words in my enum. It doesn't look like make_map is able to go from a string to the enum representation. The string I'm passing in doesn't have the underscore between the two words. Is there anyway to map string to enum, like enum to string has?

Visual Studio Intellisense

Hi.

Visual Studio 2017:
If I hover a instance of a normal enum type the name and the value are displayed.
If I hover a instance of a better enum type only the value is displayed.

Is it possible to display also the name on better enums?

Value comparison

This could be a case of missing something in the documentation but I couldn't find any mention that comparisons don't work as you'd typically expect.

That is, the following will fail with an overload resolution error:

BETTER_ENUM(Channel, int, Red, Green, Blue)

Channel channel = Channel::Red;

if(channel == Channel::Red) // channel.value_ is fine

I'll admit to not going through all of the documentation (tried a search and a few examples) since I wanted a quick evaluation of the library and I'm not interested in the more advanced capabilities but this seems like something that, if it can't be fixed, should be made fairly clear.

Thanks!

Support const iteration

Adding the following to _Iterable makes it somewhat more fully conform to what seems to be expected from a sequence/collection, when for example using with algorithms (just adding identical const versions of begin+end+iterator, plus adding value_type):

typedef const Element* const_iterator;
typedef Element value_type;

BETTER_ENUMS__CONSTEXPR const_iterator cbegin() const { return iterator(_array); }
BETTER_ENUMS__CONSTEXPR const_iterator cend() const { return iterator(_array + _size); }

Make it easier to test and/or develop on Windows

Better Enums testing currently uses CMake, Make, Python, and CxxTest. This makes it difficult to run tests on Windows without Cygwin installed.

It would be nice if running the tests didn't require Cygwin, or installing native ports of Make or Python, but only CMake and a C++ compiler. Better Enums would probably have to switch away from CxxTest to achieve this, or else commit files generated by CxxTest.

If not too difficult, it would be nice to also make it easy to develop without Cygwin, Make, or Python.

HTML and placeholder variables in markdown files

The markdown files in /tutorial and /doc contain html tags and placeholder variables such as ${prefix} that are used to generate the online project page. Sadly, the tags are fully visible and it breakes all links when viewed on github.
Example taken directly from the constexpr tutorial:

#include <iostream>

// The reason for this is explained below.
#ifndef BETTER_ENUMS_CONSTEXPR_TO_STRING
#define BETTER_ENUMS_CONSTEXPR_TO_STRING
#endif

<em>#include <enum.h></em>

<em>ENUM</em>(<em>Channel</em>, <em>int</em>, <em>Red</em> = <em>1</em>, <em>Green</em> = <em>2</em>, <em>Blue</em> = <em>3</em>)

<em>constexpr</em> Channel      channel = <em>Channel::_from_integral(2)</em>;
<em>constexpr</em> int          value = <em>channel._to_integral()</em>;

<em>constexpr</em> const char   *name = <em>channel._to_string()</em>;
<em>constexpr</em> Channel      parsed = <em>Channel::_from_string("Red")</em>;

It would be nice if users could properly view the docs directly on the project page on github or use it as offline documentation. I am not sure if this is possible without breaking http://aantron.github.io/better-enums.

Trying to figure out how to document a BETTER_ENUM in doxygen

I want to use this library but it is important that the enums are documentable.

I can document the macro invocation, and even fake parameter values

BETTER_ENUM(A, uint8_t,
  Thing1,
  Thing2
); ///< \brief Comment about enum
///< \param Thing1 the first thing

but these are not searchable.

I've tried to document the class that is generated under the hood

///\class A
///\enum A::_enumerated
///\var A::_enumerated A::Thing1 the first thing

but doxygen, expanding macros, cannot find either the class or the enum.

Any suggestions on how to proceed or am I SOL?

Case insensitive string <-> enum support?

I'm not sure if you support this, but for serialization purposes, it would be nice for case insensitivity when converting from string to enum.

Basically, a string "FOO" should map to an enumerator Foo.

Disable Clang 3.3 build

It seems to be suffering from some bit rot, and Clang 3.3 is a pretty old version. Clang 3.3 may be mentioned by the docs, so that needs to be changed, too.

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.

Enum class values are implicitly converted to integers

Hi

just a question: can such conversions be disabled somehow (like with enum class from c++11)

int a = Words::Hello;

This would be very useful - even if it is enabled only with a define before the inclusion of the enum header.

Also with enum classes we can forward declare them and even make a value out of them (if not using the enum values)

enum class A;
A op;

and with your library an enum can be forward declared like this class Words; but cannot be used for a value - only for refs and pointers (because it's a class...) - this is not that much of an issue though

Support for GCC 5.4?

I know 5.4 is not officially supported but I still report for further development.
Please support it if possible. Compile errors on Linux 64-bit gcc 5.4.0

enum.h:577:1: error: ‘namespace’ definition is not allowed here
namespace better_enums {
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:247:15: error: local class ‘class main()::Word’ shall not have static data member ‘constexpr const size_t main()::Word::_size_constant’ [-fpermissive]
4, 3, 2, 1))
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:637:9: note: in expansion of macro ‘BETTER_ENUMS_ID’
BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT(VA_ARGS));
^
enum.h:243:5: note: in expansion of macro ‘BETTER_ENUMS_ID’
BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(VA_ARGS, 64, 63, 62, 61, 60,
^
enum.h:243:21: note: in expansion of macro ‘BETTER_ENUMS_PP_COUNT_IMPL’
BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(VA_ARGS, 64, 63, 62, 61, 60,
^
enum.h:637:25: note: in expansion of macro ‘BETTER_ENUMS_PP_COUNT’
BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT(VA_ARGS));
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:665:1: error: ‘namespace’ definition is not allowed here
namespace better_enums {
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:683:1: error: a function-definition is not allowed here before ‘{’ token
{
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:688:23: error: qualified-id in declaration before ‘(’ token
Enum::_from_value_loop(Enum::_integral value, std::size_t index)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:699:24: error: qualified-id in declaration before ‘(’ token
Enum::_from_string_loop(const char name, std::size_t index)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:710:31: error: qualified-id in declaration before ‘(’ token
Enum::from_string_nocase_loop(const char *name, std::size_t index)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:720:66: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline Enum::_integral Enum::_to_integral() const
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:726:31: error: qualified-id in declaration before ‘(’ token
Enum::_from_integral_unchecked(_integral value)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:732:29: error: qualified-id in declaration before ‘(’ token
Enum::_from_integral_nothrow(integral value)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:740:57: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline Enum Enum::_from_integral(_integral value)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:739:1: note: in expansion of macro ‘BETTER_ENUMS_IF_EXCEPTIONS’
BETTER_ENUMS_IF_EXCEPTIONS(
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:748:54: error: qualified-id in declaration before ‘(’ token
ToStringConstexpr inline const char
Enum::_to_string() const
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:758:27: error: qualified-id in declaration before ‘(’ token
Enum::from_string_nothrow(const char *name)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:766:55: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline Enum Enum::_from_string(const char name)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:765:1: note: in expansion of macro ‘BETTER_ENUMS_IF_EXCEPTIONS’
BETTER_ENUMS_IF_EXCEPTIONS(
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:775:34: error: qualified-id in declaration before ‘(’ token
Enum::from_string_nocase_nothrow(const char *name)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:783:62: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline Enum Enum::from_string_nocase(const char *name)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:782:1: note: in expansion of macro ‘BETTER_ENUMS_IF_EXCEPTIONS’
BETTER_ENUMS_IF_EXCEPTIONS(
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:792:52: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline bool Enum::_is_valid(integral value)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:797:52: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline bool Enum::is_valid(const char *name)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:802:59: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline bool Enum::is_valid_nocase(const char *name)
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:807:55: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline const char
Enum::name()
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:812:67: error: qualified-id in declaration before ‘(’ token
BETTER_ENUMS_CONSTEXPR
inline Enum::_value_iterable Enum::_values()
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:817:59: error: qualified-id in declaration before ‘(’ token
ToStringConstexpr inline Enum::_name_iterable Enum::_names()
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:956:32: error: qualified-id in declaration before ‘(’ token
inline int Enum::initialize()
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:824:1: note: in expansion of macro ‘BETTER_ENUMS_DO_DEFINE_INITIALIZE’
DefineInitialize(Enum)
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
enum.h:1046:9: note: in expansion of macro ‘BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE’
BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE,
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:827:5: error: a function-definition is not allowed here before ‘{’ token
{ return a._to_integral() == b._to_integral(); }
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:829:5: error: a function-definition is not allowed here before ‘{’ token
{ return a._to_integral() != b._to_integral(); }
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:831:5: error: a function-definition is not allowed here before ‘{’ token
{ return a._to_integral() < b._to_integral(); }
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:833:5: error: a function-definition is not allowed here before ‘{’ token
{ return a._to_integral() <= b._to_integral(); }
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:835:5: error: a function-definition is not allowed here before ‘{’ token
{ return a._to_integral() > b._to_integral(); }
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^
enum.h:837:5: error: a function-definition is not allowed here before ‘{’ token
{ return a._to_integral() >= b._to_integral(); }
^
enum.h:106:28: note: in definition of macro ‘BETTER_ENUMS_ID’
#define BETTER_ENUMS_ID(x) x
^
enum.h:1039:21: note: in expansion of macro ‘BETTER_ENUMS_TYPE’
BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(
^
main.cpp:11:3: note: in expansion of macro ‘BETTER_ENUM’
BETTER_ENUM(Word, int, Hello, World)
^

Macro and header names are too plain and conflict easily

A macro named ENUM is a prime candidate for easy symbol ambiguity. And in my code base, I am seeing this. This requires me to do silly inclusion trickery like so:

// All normal includes at the top

#undef ENUM
#include <enum.h> // This one must be last in the list of include directives

ENUM(Fubar, int, One, Two, Three);

The best solution to this would be to make a more generic name for your macros. Boost does this by prefixing macros consistently. This makes them a bit more verbose, but it's a necessary annoyance when dealing with macros. I think maybe a name like BETTER_ENUM() would work just fine.

The include is odd as well. I am free to nest your header file in any directory I want, so I can resolve the issue that way. But "out of the box" your solution implies you include enum.h directly. Instead, I think you should nest your includes to avoid ambiguous includes:

#include <better/enum.h>

This might require restructuring your repository a bit, to make it obvious to people that the include is supposed to be done in a relative way like I've shown above.

There are illegal identifiers: underscore followed by uppercase letter is reserved.

better-enums uses some identifiers which are not allowed according to the C++ standard. Identifiers beginning with an underscore followed by an uppercase letter are reserved in any namespace (ref). better-enums uses three of those:

  • _Iterable
  • _PutNamesInThisScopeAlso
  • _EnumClassForSwitchStatements

What makes it worse is that these identifiers are not only in library headers, but are inserted into all users' source files via macros. Therefore, code quality checkers flag all sources using better-enums as violating standards.

Class Initializelist (on constructor) compile error

Hi, I have met a problem to use BetterEnums in class.
This is sample code.

BETTER_ENUM(EnumTest, uint32, NONE = 0, APPLE)

class Apple
{
public:
Apple() : test(EnumTest::APPLE) {}
Apple(int k) {}
EnumTest test;
};


consoleapplication1.cpp(32): error C2248: 'EnumTest::EnumTest': cannot access private member declared in class 'EnumTest'
consoleapplication1.cpp(26): note: see declaration of 'EnumTest::EnumTest'
consoleapplication1.cpp(26): note: see declaration of 'EnumTest'

I could solve this problem by this code.

BETTER_ENUM(EnumTest, uint32, NONE = 0, APPLE)

class Apple
{
public:
Apple() : test(EnumTest::APPLE) {}
Apple(int k) : test(EnumTest::APPLE) {}
EnumTest test;
};

or

class Apple
{
public:
Apple() {}
Apple(int k) {}
EnumTest test = EnumTest::APPLE;
};

Thanks.

Warning: use of old-style cast

In Qt Creator, with the Clang code model selected (help -> about plugins -> C++), I see the following warning:

Semantic Issue -Wold-style-cast
23:5: warning: use of old-style cast
enum.h:1089:21: note: expanded from macro 'BETTER_ENUM'
enum.h:679:23: note: expanded from macro 'BETTER_ENUMS_TYPE'
enum.h:500:13: note: expanded from macro 'BETTER_ENUMS_EAT_ASSIGN'
:0:0: note: (skipping 4 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
enum.h:114:28: note: expanded from macro 'BETTER_ENUMS_ID'
enum.h:114:28: note: expanded from macro 'BETTER_ENUMS_ID'
enum.h:114:28: note: expanded from macro 'BETTER_ENUMS_ID'

(If I have the default code model selected, I get warnings whenever I use BETTER_ENUM(), and code completion/coloring doesn't work for those enums, so I kinda have to use the clang code model)

Put enum.h inside include/betterenums subdirectory.

You should put enum.h inside an include/betterenums subdirectory of your Git repository. This would allow superproject build scripts to clone your Git repo as-is and add -I superproject/thirdpartylibs/betterenums/include compiler flags where appropriate.

To include your header, we would use

#include <betterenums/enum.h>

which would avoid collisions with other headers named enum.h.

Can and ENUM-declared enum be a member variable type?

It seems it cannot, As soon as I declare a member variable of a BETTER_ENUM, say Colour, the compiler says:

error: ‘Colour::Colour()’ is private within this context

and the constructor of the class where it is declared becomes deleted.

Any ideas?

Microsoft Visual C++ Compiler error C2248 if using a Better Enum as a member in a class with a user-defined constructor

Declaring a Better Enum as a member variable in a class without a user-defined constructor results in a C2248 compiler error (tested with both MSVC 12.0 + MSVC 14.0, using /W3).

The C2248 error does not occur if the default constructor is generated by the compiler (and no other constructors are defined).

Source code to reproduce the issue:

#include <iostream>

#include <enum.h>

namespace example {
  BETTER_ENUM(Boolean, bool, TRUE = true, FALSE = false)

  class Example {
	public:
	 Example() {
	   // NOOP
	 }

	 // 1. Workaround
//     Example() : boolean_enum_{Boolean::FALSE} {
//       // NOOP
//     }

	 // Microsoft Visual C++ Compiler Error C2248.
	 Boolean boolean_enum_;

	 // 2. Workaround
//     Boolean boolean_enum_{Boolean::FALSE};
  };
}  // namespace example

int main() {
  example::Example example{};
  std::cout << example.boolean_enum_._to_string();
}

Compiler output (in German):

Fehler: C2248: "example::Boolean::Boolean": Kein Zugriff auf private Member, dessen Deklaration in der example::Boolean-Klasse erfolgte.

Suggestion

I think Better Enums should work the same as a built-in enum class. Due to this error I cannot use Better Enums in production code. This is a severe issue, since users have to modify client code if upgrading from built-in enumerations to Better Enums.

Workarounds

There are at least two possible workaround:

  1. Initialize the Better Enum member variable in the initializer list of the constructor (see code comment 1).
  2. Initialize the Better Enum member variable with a member initializer (see code comment 2).

Declare inside class

I want to make a role field for a user. So I try to compile this code:

struct User{
    BETTER_ENUM(Role, int,
                user,
                driver)
};

and it tells me Missing '}' at end of definition of 'User' at the first line and Extraneous closing brace ('}') at the last line. Compiling using Xcode 7.3.1. The issue is how to create enum enclosed inside a class?

Compare the enum class with enumerated values

Hi,

I've been playing around with better enums recently and I was trying to compare between the enum class and its enumerated values:

auto a = Hello::World;
if (a == Hello::World)
...

As stated in some other issues, this triggers a compilation error.
I dug inside the enum.h file and foudn a way to patch macro definitions to include support for such comparison cases.

However, I'm not entirely sure this patch fits well with the rest of the library, I've been testing it against my own use cases and it seems to do the job for me.

Are you interested in a patch proposal ? If so, should I create a branch directly on your repository or do you prefer a diff file attached to this ticket ?

Regards.

CMake Package and Installation for Better Enums

In issue #24 this has been already discussed.

If Better Enums would provide a CMake Package, it would be much easier to use by clients.

Don't get me wrong: Copy & Pasting one header file isn't hard, but it is against the Don't Repeat Yourself Principle (DRYP). Currently I implemented a custom (old-style) FindBetterEnums.cmake CMake Find Module, but that is also a poor man's solution.

I think it would be much cleaner to provide a CMake package together with a proper CMake Installation.

I could provide a clean and modern CMakeLists.txt file for the project via a PR if it is desired (I have a bit of experience with CMake). @rcdailey already provided one, but it haven't been included in the master?


If this issue isn't rejected I would install Better Enum in a way, that #includes would look like the following (see #11):

#include <better_enum/enum.h>
#include <better_enum/n4428.h>

IMO that would be a little clearer.

Export from DLL

How do I use the BETTER_ENUM macro if I need to add declspec(_dllexport) ?

Traits class

I would be nice to have a traits class to detect whether a type is a "better enum" (akin to std::is_enum)

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"); }
};

support for string_view

Hi

Have you considered adding support for string_view for the _from_string methods?
It doesn't convert to char * so _names_match, _from_string and _from_string_loop would need to be overloaded.

BETTER_ENUM(Channel, char, Red = 1, Green, Blue)
int main() {
  std::experimental::string_view s("Blue");
  auto c = Channel::_from_string_nothrow(s);
  std::cout << *c << std::endl;
  return(0);
}

Eliminating conversions to unscoped enum type

Figured I'd open an issue for this, since it was discussed in multiple places (#22, #23).

I have another suggestion besides making "strict conversions" the default: eliminate implicit conversions to enums completely. IIRC they are only needed for switch, for which we could provide a function with a name like _switch:

switch(my_enum._switch()) {
    case Foo::A: break;
    case Foo::B: break;
}

We could also make this operator +, if you can bear all the operator +s :)

switch(+my_enum) { ...

The conversion this would perform would be to an unscoped enum type, so we could use the Foo::A syntax in cases without having to prepend the existing operator +.

cc @cheparukhin @mbevin @rcdailey

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.

Eclipst CDT complains about class Enum's default ctor

Eclipst CDT complains about the default constructor for class Enum - it gives a warning about the lack of explicit initialization of all data members.

Assuming no negative reprecussions, I suggest replacing this:

#ifndef BETTER_ENUMS_DEFAULT_CONSTRUCTOR
#   define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum)                              \
      private:                                                                 \
        Enum() { }
#endif

with this:

#ifndef BETTER_ENUMS_DEFAULT_CONSTRUCTOR
#   define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum)                              \
      private:                                                                 \
        Enum() : _value() { }
#endif

i.e. explicitly default-initializing the _value() field.

Switch not working with strict enums enabled

switch() doesn't seem to work when combined with BETTER_ENUMS_STRICT_CONVERSION. This is because it's using BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE, which creates a "copy" scoped enum with the same enumerators. The problem is that enumerators from _enumerated (which are also specified in each case section) cannot be compared to the like-named enumerators in the "copy" version.

Any reason that in the strict case, the implicit typecast operator in the Enum class isn't just returning _enumerated and not this dummy scoped enum? Oddly though, the code compiles fine on MSVC 14 but on Android NDK GCC 4.9, it does not work:

MSRData.cpp: In constructor 'CMSRData::CMSRData(const char*, MsrEncryptionStatus)':
MSRData.cpp:42:36: error: could not convert 'Ksn' from 'MsrEncryptionStatus::_enumerated' to 'better_enums::_data_MsrEncryptionStatus::_EnumClassForSwitchStatements'
          case MsrEncryptionStatus::Ksn:
                                    ^
MSRData.cpp:51:36: error: could not convert 'None' from 'MsrEncryptionStatus::_enumerated' to 'better_enums::_data_MsrEncryptionStatus::_EnumClassForSwitchStatements'
          case MsrEncryptionStatus::None:
                                    ^
MSRData.cpp:55:36: error: could not convert 'Dukpt' from 'MsrEncryptionStatus::_enumerated' to 'better_enums::_data_MsrEncryptionStatus::_EnumClassForSwitchStatements'
          case MsrEncryptionStatus::Dukpt:
                                    ^

versions of the _from_string() functions taking const std::string&

At the moment, the _from_string() function, its variants, and some additional functions such as _is_valid() take their input string as a const char* , meaning that you can't pass an std::string directly. I would expect to be able to do this without any conversions, wtih std::string being the preferred type for (a lot of / most) string work in C++.

If this is not intentional, I suggest variants be added which take const std::string& parameters.

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

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.

setting enumerations from strings

I am migrating from a 'smart enum' library based on what used to be 'BOOST_ENUM'. I noticed that the _from_string function is static, and recall having been bitten by this before in that library.

My problem is that it is possible to call this as a member function on an existing enumeration with rather unpleasant consequences.

BETTER_ENUM(Enum, int, A, B, C)
Enum X = Enum::_from_string("A") 
X._from_string("B"); // legal, but no change of X

I would much prefer the function to be non-static, in order to make sure that at the end X == Enum::B holds, and (for example) having a factory function akin to what is present in the standard library, such as:

X = make_enum<Enum>("A"); 
X = make_enum<Enum>(2); 

Also, I am missing constructors that allow for example:

Enum X("A")

Is there a good reason to not allow this?

Microsoft Visual C++ Compiler warning C4800 if using bool as the underlying type of a Better Enum

Declaring a Better Enum with a underlying type of bool results in a C4800 compiler warning (tested with both MSVC 12.0 + MSVC 14.0, using /W3).

Source code to reproduce the issue:

BETTER_ENUM(Boolean, bool, TRUE = true, FALSE = false)

Compiler output (in German):

"example::Boolean::_enumerated": Variable wird auf booleschen Wert ("True" oder "False") gesetzt (Auswirkungen auf Leistungsverhalten möglich)

Suggestion

I think Better Enums should work the same as a built-in enum class. The following source code does not raise a compiler warning:

enum class Boolean : bool {
  TRUE = true,
  FALSE = false
};

Better Enums with CUDA?

Hi, I have been trying to use Better Enums with CUDA, in a .cu file.

When supplying --expt-relaxed-constexpr to NVCC, this works alright for the most part. However, when initializing the enum members, NVCC does something very strange.

Here is my testing code:

#include "enum.h"

BETTER_ENUM(Channel, char, Red = 1, Green, Blue);

int main() { }

Compile with nvcc constexpr-init.cu -std=c++11 -o constexpr-init

I get the following errors that are not understandable to me:

constexpr-init.cu:3:2362: error: lvalue required as left operand of assignment
 BETTER_ENUM(Channel, char, Red = 1, Green, Blue);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ^
constexpr-init.cu: In static member function 'static constexpr Channel::_optional Channel::_from_integral_nothrow(Channel::_integral)':
constexpr-init.cu:3:0: error: body of constexpr function 'static constexpr Channel::_optional Channel::_from_integral_nothrow(Channel::_integral)' not a return-statement
 BETTER_ENUM(Channel, char, Red = 1, Green, Blue);
 
constexpr-init.cu: In static member function 'static constexpr Channel::_optional Channel::_from_string_nothrow(const char*)':
constexpr-init.cu:3:0: error: body of constexpr function 'static constexpr Channel::_optional Channel::_from_string_nothrow(const char*)' not a return-statement
constexpr-init.cu: In static member function 'static constexpr Channel::_optional Channel::_from_string_nocase_nothrow(const char*)':
constexpr-init.cu:3:0: error: body of constexpr function 'static constexpr Channel::_optional Channel::_from_string_nocase_nothrow(const char*)' not a return-statement
constexpr-init.cu: In static member function 'static constexpr Channel::_value_iterable Channel::_values()':
constexpr-init.cu:3:0: error: body of constexpr function 'static constexpr Channel::_value_iterable Channel::_values()' not a return-statement

NVCC creates .cpp files that are passed to the host compiler. These files can be inspected by adding the --keep parameter to the command line.

If you do that and inspect the file, you will find the macro expansion somewhere, which looks like this:

namespace better_enums { namespace _data_Channel { }}class Channel { typedef better_enums::optional< Channel>  _optional; typedef better_enums::optional< unsigned long>  _optional_index; public: typedef char _integral; enum _enumerated: char { Red = 1, Green, Blue}; constexpr Channel(_enumerated value) : _value(value) { } constexpr operator _enumerated() const { return (_enumerated)(_value); } constexpr _integral _to_integral() const; static constexpr Channel _from_integral(_integral value); static constexpr Channel _from_integral_unchecked(_integral value); static constexpr _optional _from_integral_nothrow(_integral value); inline const char *_to_string() const; static constexpr Channel _from_string(const char * name); static constexpr _optional _from_string_nothrow(const char * name); static constexpr Channel _from_string_nocase(const char * name); static constexpr _optional _from_string_nocase_nothrow(const char * name); static constexpr bool _is_valid(_integral value); static constexpr bool _is_valid(const char * name); static constexpr bool _is_valid_nocase(const char * name); typedef better_enums::_Iterable< Channel>  _value_iterable; typedef better_enums::_Iterable< const char *>  _name_iterable; typedef better_enums::_Iterable< Channel> ::iterator _value_iterator; typedef better_enums::_Iterable< const char *> ::iterator _name_iterator; static constexpr const std::size_t _size_constant = (3); static constexpr std::size_t _size() { return _size_constant; } static constexpr const char *_name(); static constexpr _value_iterable _values(); static inline _name_iterable _names(); _integral _value; private: Channel() : _value((0)) { } constexpr explicit Channel(const _integral &value) : _value(value) { } static inline int initialize(); static constexpr _optional_index _from_value_loop(_integral value, std::size_t index = 0); static constexpr _optional_index _from_string_loop(const char * name, std::size_t index = 0); static constexpr _optional_index _from_string_nocase_loop(const char * name, std::size_t index = 0); friend struct better_enums::_initialize_at_program_start< Channel> ; }; namespace better_enums { namespace _data_Channel { static _initialize_at_program_start< Channel>  _force_initialization; enum _PutNamesInThisScopeAlso { Red = 1, Green, Blue}; constexpr const Channel _value_array[] = {(Channel::Red = (1)), (Channel::Green), (Channel::Blue)}; constexpr const char *_the_raw_names[] = {("Red = 1"), ("Green"), ("Blue")}; constexpr const char *const *_raw_names() { return _the_raw_names; } inline char *_name_storage() { static char storage[] = "Red = 1,Green,Blue,"; return storage; } inline const char **_name_array() { static const char *value[Channel::_size_constant]; return value; } inline bool &_initialized() { static bool value = false; return value; } }}constexpr const Channel operator+(Channel::_enumerated enumerated) { return static_cast< Channel>(enumerated); } constexpr Channel::_optional_index Channel::_from_value_loop(_integral value, std::size_t index) { return ((index == _size()) ? _optional_index() : ((((((better_enums::_data_Channel::_value_array)[index])._value) == value) ? ((_optional_index)(index)) : (_from_value_loop(value, index + (1)))))); } constexpr Channel::_optional_index Channel::_from_string_loop(const char *name, std::size_t index) { return ((index == _size()) ? _optional_index() : ((::better_enums::_names_match(better_enums::_data_Channel::_raw_names()[index], name) ? ((_optional_index)(index)) : (_from_string_loop(name, index + (1)))))); } constexpr Channel::_optional_index Channel::_from_string_nocase_loop(const char *name, std::size_t index) { return ((index == _size()) ? _optional_index() : ((::better_enums::_names_match_nocase(better_enums::_data_Channel::_raw_names()[index], name) ? ((_optional_index)(index)) : (_from_string_nocase_loop(name, index + (1)))))); } constexpr Channel::_integral Channel::_to_integral() const { return (_integral)(_value); } constexpr Channel Channel::_from_integral_unchecked(_integral value) { return static_cast< _enumerated>(value); } constexpr Channel::_optional Channel::_from_integral_nothrow(_integral value) { return ::better_enums::_map_index< Channel> (better_enums::_data_Channel::_value_array, _from_value_loop(value)); } constexpr Channel Channel::_from_integral(_integral value) { return ::better_enums::_or_throw(_from_integral_nothrow(value), "Channel::_from_integral: invalid argument"); } inline const char *Channel::_to_string() const { return ::better_enums::_or_null(::better_enums::_map_index< const char *> (better_enums::_data_Channel::_name_array(), _from_value_loop(::better_enums::continue_with(initialize(), _value)))); } constexpr Channel::_optional Channel::_from_string_nothrow(const char *name) { return ::better_enums::_map_index< Channel> (better_enums::_data_Channel::_value_array, _from_string_loop(name)); } constexpr Channel Channel::_from_string(const char *name) { return ::better_enums::_or_throw(_from_string_nothrow(name), "Channel::_from_string: invalid argument"); } constexpr Channel::_optional Channel::_from_string_nocase_nothrow(const char *name) { return ::better_enums::_map_index< Channel> (better_enums::_data_Channel::_value_array, _from_string_nocase_loop(name)); } constexpr Channel Channel::_from_string_nocase(const char *name) { return ::better_enums::_or_throw(_from_string_nocase_nothrow(name), "Channel::_from_string_nocase: invalid argument"); } constexpr bool Channel::_is_valid(_integral value) { return _from_value_loop(value); } constexpr bool Channel::_is_valid(const char *name) { return _from_string_loop(name); } constexpr bool Channel::_is_valid_nocase(const char *name) { return _from_string_nocase_loop(name); } constexpr const char *Channel::_name() { return "Channel"; } constexpr Channel::_value_iterable Channel::_values() { return _value_iterable(better_enums::_data_Channel::_value_array, _size()); } inline Channel::_name_iterable Channel::_names() { return _name_iterable(better_enums::_data_Channel::_name_array(), ::better_enums::continue_with(initialize(), _size())); } inline int Channel::initialize() { if (better_enums::_data_Channel::_initialized()) { return 0; }  ::better_enums::_trim_names(better_enums::_data_Channel::_raw_names(), better_enums::_data_Channel::_name_array(), better_enums::_data_Channel::_name_storage(), _size()); better_enums::_data_Channel::_initialized() = true; return 0; } constexpr bool operator==(const Channel &a, const Channel &b) { return (a._to_integral()) == (b._to_integral()); } constexpr bool operator!=(const Channel &a, const Channel &b) { return (a._to_integral()) != (b._to_integral()); } constexpr bool operator<(const Channel &a, const Channel &b) { return (a._to_integral()) < (b._to_integral()); } constexpr bool operator<=(const Channel &a, const Channel &b) { return (a._to_integral()) <= (b._to_integral()); } constexpr bool operator>(const Channel &a, const Channel &b) { return (a._to_integral()) > (b._to_integral()); } constexpr bool operator>=(const Channel &a, const Channel &b) { return (a._to_integral()) >= (b._to_integral()); }

(Sorry for the no spaces, but this is what I get out).
The error occurs at character 2362 which seems to be the expression Channel::Red = (1) in the following statement:

constexpr const Channel _value_array[] = {(Channel::Red = (1)), (Channel::Green), (Channel::Blue)};

This is the end of my investigations, I don't know where to go from here.

I know that it's probably the NVCC that's broken, but can you think of a way to make this initialization work?

Extend default size limit beyond 64

I exceeded the implicit enum size limit so had to extend the BETTER_ENUMS__PP_COUNT-etc macros to support more than 64 elements ... perhaps 128 or something might be a good new limit for example.

Binary operator ambiguity

Consider this example:

BETTER_ENUM(TestEnum, int, One, Two);

int main()
{
    TestEnum mine = TestEnum::One;

    if (mine == TestEnum::One)
    {
    }
}

The comparison using == above fails on MSVC and GCC with the following:

main.cpp:1193:14: error: ambiguous overload for 'operator==' (operand types are 'TestEnum' and 'TestEnum::_enumerated')
     if (mine == TestEnum::One)
         ~~~~~^~~~~~~~~~~
main.cpp:1193:14: note: candidate: operator==(TestEnum::_enumerated, TestEnum::_enumerated) <built-in>
main.cpp:1193:14: note: candidate: operator==(int, int) <built-in>

Since you're using an unscoped enumeration internally, a direct comparison cannot be performed because the compiler can cast _enumerated either to int or TestEnum.

Yes, I realize I can use the + operator but I find this to be unintuitive semantically and unnecessary.

As a test I added an additional operator overload:

BETTER_ENUMS_CONSTEXPR_ inline bool operator ==(const Enum &a, const Enum::_enumerated &b)  \
    { return a._to_integral() == b; }                           \

This fixed the compiler error. I feel that the Enum class should explicitly handle operations on its enumerated type. I also find it odd that there is no way to grab the internal enumerated type that a Enum variable represents, much like Enum::_to_integer() but instead something like Enum::_to_enum(), which has a return type of Enum::_enumerated.

Thoughts? I'm happy to contribute a PR for this if you feel that this is a good addition.

Fail on MSVC 9.0

The following does not compile with MSVC 9.0:

include "stdafx.h"

include "enum.h"

ENUM(immersion_medium, int, unknown = -1, oil = 0, water, dry, silicone, glycerol)

int _tmain(int argc, _TCHAR* argv[])
{
immersion_medium::_from_integral( 0 ) ;

return 0;

}

error LNK2019: unresolved external symbol...

A copy constructor seems to be missing.

Maintain the traits version

See old discussion of tradeoffs between traits and objects. Objects have some additional flaws.

  • Update the traits implementation based on improvements to the object version in the last year or so. Traits and objects implementations should be able to share a lot of code.
  • Make traits and objects alternative interfaces with equal status in terms of maintenance and documentation.

Traits branch: https://github.com/aantron/better-enums/tree/traits

attach metadata to enum values ?

Hi, what would be your approach to attach metadata (such as descriptions, alternate representations ...) to each enum value ?

Example 1:

BETTER_ENUM(Direction, int, {
  {up, "Upwards"},
  {down, "Downwards"},
  {left, "Leftwards"},
  {right, "Rightwards"}
})
Direction d = Direction::up;
std::cout << d._meta(); // Upwards

Example 2:

BETTER_ENUM(Color, int, {
  {AliceBlue, {"#F0F8FF", 215, 223, 236}},
  {Aqua, {"#00FFFF", 0, 255, 255}}, 
  ...})
Color c = Color::Aqua;
std::cout << c._meta()[0]; // #00FFFF

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.