Option to opt in to implicit conversion to enum class instead of enum.

A Better Enum is normally implicitly convertible to its internal enum type,
which makes it then implicitly convertible to an integer as well. The former
conversion is necessary for Better Enums to be usable in switch statements.
This change makes it possible to define BETTER_ENUMS_SAFER_SWITCH, which makes
Better Enums convert to an enum class, preventing the implicit conversion to
integers. The drawback is that switch cases have to be written as

    case Enum::_Case::A:

instead of

    case Enum::A:
This commit is contained in:
Anton Bachin 2015-05-18 00:53:00 -05:00
parent 10c9977a9c
commit 1cfe53e827
2 changed files with 22 additions and 9 deletions

27
enum.h
View File

@ -3,8 +3,8 @@
#pragma once #pragma once
#ifndef _BETTER_ENUM_ENUM_H_ #ifndef _BETTER_ENUMS_ENUM_H_
#define _BETTER_ENUM_ENUM_H_ #define _BETTER_ENUMS_ENUM_H_
@ -14,9 +14,9 @@
#ifdef BETTER_ENUM_PP_MAP_FILE #ifdef BETTER_ENUMS_MACRO_FILE
#include BETTER_ENUM_PP_MAP_FILE #include BETTER_ENUMS_MACRO_FILE
#else #else
@ -331,7 +331,7 @@
X(f, l, 16) X(f, l, 17) X(f, l, 18) X(f, l, 19) X(f, l, 20) X(f, l, 21) \ X(f, l, 16) X(f, l, 17) X(f, l, 18) X(f, l, 19) X(f, l, 20) X(f, l, 21) \
X(f, l, 22) X(f, l, 23) X(f, l, 22) X(f, l, 23)
#endif // #ifdef BETTER_ENUM_PP_MAP_FILE #endif // #ifdef BETTER_ENUMS_MACRO_FILE
@ -590,6 +590,19 @@ constexpr const _Iterable<const char*> _names{_name_array, _size}; \
#define _ENUM_NS(EnumType) _enum::_data_ ## EnumType #define _ENUM_NS(EnumType) _enum::_data_ ## EnumType
#define _ENUM_NOT_FOUND ((size_t)-1) #define _ENUM_NOT_FOUND ((size_t)-1)
#ifndef BETTER_ENUMS_SAFER_SWITCH
#define _ENUM_CONVERSION_FOR_SWITCH(Integral, ...) \
constexpr operator _Enumerated() const { return _value; }
#else
#define _ENUM_CONVERSION_FOR_SWITCH(Integral, ...) \
enum class _Case : Integral { __VA_ARGS__ }; \
constexpr operator _Case() const { return (_Case)_value; }
#endif // #ifndef BETTER_ENUMS_SAFER_SWITCH
#define _ENUM_TYPE(EnumType, Integral, ...) \ #define _ENUM_TYPE(EnumType, Integral, ...) \
class EnumType : public _ENUM_NS(EnumType)::_Base { \ class EnumType : public _ENUM_NS(EnumType)::_Base { \
protected: \ protected: \
@ -658,7 +671,7 @@ class EnumType : public _ENUM_NS(EnumType)::_Base { \
return _from_string_nocase_loop(name, false) != _ENUM_NOT_FOUND; \ return _from_string_nocase_loop(name, false) != _ENUM_NOT_FOUND; \
} \ } \
\ \
constexpr operator _Enumerated() const { return _value; } \ _ENUM_CONVERSION_FOR_SWITCH(Integral, __VA_ARGS__); \
\ \
constexpr static auto &_values = _ENUM_NS(EnumType)::_values; \ constexpr static auto &_values = _ENUM_NS(EnumType)::_values; \
constexpr static auto &_names = _ENUM_NS(EnumType)::_names; \ constexpr static auto &_names = _ENUM_NS(EnumType)::_names; \
@ -721,4 +734,4 @@ constexpr const EnumType operator +(_ENUM_NS(EnumType)::_Base base) \
#endif // #ifndef _BETTER_ENUM_ENUM_H_ #endif // #ifndef _BETTER_ENUMS_ENUM_H_

View File

@ -25,8 +25,8 @@
# somewhere in your include path. # somewhere in your include path.
# 1. Run python pp_map_gen.py 512 128 > MACRO_FILE # 1. Run python pp_map_gen.py 512 128 > MACRO_FILE
# 2. Build your code with an additional compiler flag: # 2. Build your code with an additional compiler flag:
# - for gcc and clang, -DBETTER_ENUM_PP_MAP_FILE='<MACRO_FILE>' # - for gcc and clang, -BETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
# - for VC++, /DBETTER_ENUM_PP_MAP_FILE='<MACRO_FILE>' # - for VC++, /BETTER_ENUMS_MACRO_FILE='<MACRO_FILE>'
# or use any other method of getting these macros declared. # or use any other method of getting these macros declared.
# 3. Compile your code. Your macro file should be included, and enum.h should # 3. Compile your code. Your macro file should be included, and enum.h should
# happily work with whatever limits you chose. # happily work with whatever limits you chose.