mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
Converted to traits interface.
This commit is contained in:
parent
2895867224
commit
216f026fe1
273
enum.h
273
enum.h
@ -94,7 +94,7 @@ namespace _enum {
|
|||||||
template <typename EnumType, typename Iterator>
|
template <typename EnumType, typename Iterator>
|
||||||
class _Iterable;
|
class _Iterable;
|
||||||
|
|
||||||
template <typename EnumType, typename Derived>
|
template <typename Derived>
|
||||||
class _BaseIterator {
|
class _BaseIterator {
|
||||||
public:
|
public:
|
||||||
Derived& operator ++()
|
Derived& operator ++()
|
||||||
@ -112,12 +112,12 @@ class _BaseIterator {
|
|||||||
|
|
||||||
template <typename EnumType>
|
template <typename EnumType>
|
||||||
class _ValueIterator :
|
class _ValueIterator :
|
||||||
public _BaseIterator<EnumType, _ValueIterator<EnumType>> {
|
public _BaseIterator<_ValueIterator<EnumType>> {
|
||||||
|
|
||||||
using _Super = _BaseIterator<EnumType, _ValueIterator<EnumType>>;
|
using _Super = _BaseIterator<_ValueIterator<EnumType>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr EnumType operator *() const
|
constexpr typename EnumType::Enumerated operator *() const
|
||||||
{ return EnumType::_value_array[_Super::_index]; }
|
{ return EnumType::_value_array[_Super::_index]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -128,9 +128,9 @@ class _ValueIterator :
|
|||||||
|
|
||||||
template <typename EnumType>
|
template <typename EnumType>
|
||||||
class _NameIterator :
|
class _NameIterator :
|
||||||
public _BaseIterator<EnumType, _NameIterator<EnumType>> {
|
public _BaseIterator<_NameIterator<EnumType>> {
|
||||||
|
|
||||||
using _Super = _BaseIterator<EnumType, _NameIterator<EnumType>>;
|
using _Super = _BaseIterator<_NameIterator<EnumType>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const char* operator *() const
|
const char* operator *() const
|
||||||
@ -148,8 +148,8 @@ class _Iterable {
|
|||||||
using iterator = Iterator;
|
using iterator = Iterator;
|
||||||
|
|
||||||
constexpr iterator begin() const { return iterator(0); }
|
constexpr iterator begin() const { return iterator(0); }
|
||||||
constexpr iterator end() const { return iterator(EnumType::_size); }
|
constexpr iterator end() const { return iterator(EnumType::size); }
|
||||||
constexpr size_t size() const { return EnumType::size(); }
|
constexpr size_t size() const { return EnumType::size; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr _Iterable() { };
|
constexpr _Iterable() { };
|
||||||
@ -192,7 +192,7 @@ class _eat_assign {
|
|||||||
/// Prepends its second argument with the cast `(_eat_assign<UnderlyingType>)`
|
/// Prepends its second argument with the cast `(_eat_assign<UnderlyingType>)`
|
||||||
/// in order to make it usable in initializer lists. See `_eat_assign`.
|
/// in order to make it usable in initializer lists. See `_eat_assign`.
|
||||||
#define _ENUM_EAT_ASSIGN_SINGLE(UnderlyingType, expression) \
|
#define _ENUM_EAT_ASSIGN_SINGLE(UnderlyingType, expression) \
|
||||||
((_enum::_eat_assign<UnderlyingType>)expression)
|
((_enum::_eat_assign<UnderlyingType>)UnderlyingType::expression)
|
||||||
|
|
||||||
/// Prepends each of its arguments with the casts
|
/// Prepends each of its arguments with the casts
|
||||||
/// `(_eat_assign<UnderlyingType>)`, creating the elements of an initializer
|
/// `(_eat_assign<UnderlyingType>)`, creating the elements of an initializer
|
||||||
@ -387,30 +387,27 @@ static inline const char * const* _processNames(const char * const *rawNames,
|
|||||||
return processedNames;
|
return processedNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _ENUM_TAG(EnumType) _tag_ ## EnumType
|
template <typename EnumType> class _GeneratedArrays;
|
||||||
#define _ENUM_TAG_DECLARATION(EnumType) \
|
|
||||||
namespace _enum { \
|
|
||||||
struct _ENUM_TAG(EnumType); \
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Tag> class _GeneratedArrays;
|
} // namespace _enum
|
||||||
|
|
||||||
#define _ENUM_ARRAYS(EnumType, Integral, Tag, ...) \
|
#define _ENUM_ARRAYS(EnumType, IntegralType, ...) \
|
||||||
|
enum class EnumType : IntegralType { __VA_ARGS__ }; \
|
||||||
|
\
|
||||||
namespace _enum { \
|
namespace _enum { \
|
||||||
\
|
\
|
||||||
template <> \
|
template <> \
|
||||||
class _GeneratedArrays<Tag> { \
|
class _GeneratedArrays<EnumType> { \
|
||||||
protected: \
|
protected: \
|
||||||
using _Integral = Integral; \
|
using Integral = IntegralType; \
|
||||||
|
using Enumerated = EnumType; \
|
||||||
\
|
\
|
||||||
public: \
|
public: \
|
||||||
constexpr static const char* _name = #EnumType; \
|
constexpr static const char* name = #EnumType; \
|
||||||
\
|
|
||||||
enum _Enumerated : _Integral { __VA_ARGS__ }; \
|
|
||||||
\
|
\
|
||||||
protected: \
|
protected: \
|
||||||
constexpr static _Enumerated _value_array[] = \
|
constexpr static Enumerated _value_array[] = \
|
||||||
{ _ENUM_EAT_ASSIGN(_Enumerated, __VA_ARGS__) }; \
|
{ _ENUM_EAT_ASSIGN(Enumerated, __VA_ARGS__) }; \
|
||||||
\
|
\
|
||||||
constexpr static const char *_name_array[] = \
|
constexpr static const char *_name_array[] = \
|
||||||
{ _ENUM_STRINGIZE(__VA_ARGS__) }; \
|
{ _ENUM_STRINGIZE(__VA_ARGS__) }; \
|
||||||
@ -420,94 +417,92 @@ template <typename Tag> class _GeneratedArrays;
|
|||||||
|
|
||||||
#define _ENUM_NOT_FOUND ((size_t)-1)
|
#define _ENUM_NOT_FOUND ((size_t)-1)
|
||||||
|
|
||||||
template <typename Tag>
|
namespace enum_ {
|
||||||
class _Enum : public _GeneratedArrays<Tag> {
|
|
||||||
|
template <typename EnumType>
|
||||||
|
class traits : public _enum::_GeneratedArrays<EnumType> {
|
||||||
protected:
|
protected:
|
||||||
using _arrays = _GeneratedArrays<Tag>;
|
using _arrays = _enum::_GeneratedArrays<EnumType>;
|
||||||
using _arrays::_value_array;
|
using _arrays::_value_array;
|
||||||
using _arrays::_name_array;
|
using _arrays::_name_array;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using typename _arrays::_Enumerated;
|
using typename _arrays::Enumerated;
|
||||||
using typename _arrays::_Integral;
|
using typename _arrays::Integral;
|
||||||
|
|
||||||
constexpr static const size_t _size =
|
constexpr static const size_t size =
|
||||||
sizeof(_value_array) / sizeof(_Enumerated);
|
sizeof(_value_array) / sizeof(Enumerated);
|
||||||
static_assert(_size > 0, "no constants defined in enum type");
|
static_assert(size > 0, "no constants defined in enum type");
|
||||||
|
|
||||||
constexpr static const _Enumerated _first = _value_array[0];
|
constexpr static const Enumerated first = _value_array[0];
|
||||||
constexpr static const _Enumerated _last = _value_array[_size - 1];
|
constexpr static const Enumerated last = _value_array[size - 1];
|
||||||
constexpr static const _Enumerated _min = _findMin(_value_array, _size);
|
constexpr static const Enumerated min =
|
||||||
constexpr static const _Enumerated _max = _findMax(_value_array, _size);
|
_enum::_findMin(_value_array, size);
|
||||||
|
constexpr static const Enumerated max =
|
||||||
|
_enum::_findMax(_value_array, size);
|
||||||
|
|
||||||
constexpr static const size_t _span = _max - _min + 1;
|
constexpr static const size_t span =
|
||||||
|
(Integral)max - (Integral)min + 1;
|
||||||
|
|
||||||
_Enum() = delete;
|
constexpr static Integral to_integral(Enumerated value)
|
||||||
constexpr _Enum(_Enumerated constant) : _value(constant) { }
|
|
||||||
|
|
||||||
constexpr _Integral to_integral() const
|
|
||||||
{
|
{
|
||||||
return _value;
|
return (Integral)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static const _Enum _from_integral(_Integral value)
|
constexpr static const Enumerated from_integral(Integral value)
|
||||||
{
|
{
|
||||||
return _value_array[_from_int_loop(value, true)];
|
return _value_array[_from_int_loop(value, true)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static const _Enum _from_integral_unchecked(_Integral value)
|
constexpr static const Enumerated from_integral_unchecked(Integral value)
|
||||||
{
|
{
|
||||||
return (_Enumerated)value;
|
return (Enumerated)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* to_string() const
|
static const char* to_string(Enumerated value)
|
||||||
{
|
{
|
||||||
_processNames();
|
_processNames();
|
||||||
|
|
||||||
for (size_t index = 0; index < _size; ++index) {
|
for (size_t index = 0; index < size; ++index) {
|
||||||
if (_value_array[index] == _value)
|
if (_value_array[index] == value)
|
||||||
return _processedNames[index];
|
return _processedNames[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::domain_error("Enum::_to_string: invalid enum value");
|
throw std::domain_error("Enum::_to_string: invalid enum value");
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static const _Enum _from_string(const char *name)
|
constexpr static const Enumerated from_string(const char *name)
|
||||||
{
|
{
|
||||||
return _value_array[_from_string_loop(name, true)];
|
return _value_array[_from_string_loop(name, true)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static const _Enum _from_string_nocase(const char *name)
|
constexpr static const Enumerated from_string_nocase(const char *name)
|
||||||
{
|
{
|
||||||
return _value_array[_from_string_nocase_loop(name, true)];
|
return _value_array[_from_string_nocase_loop(name, true)];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static bool _is_valid(_Integral value)
|
constexpr static bool is_valid(Integral value)
|
||||||
{
|
{
|
||||||
return _from_int_loop(value, false) != _ENUM_NOT_FOUND;
|
return _from_int_loop(value, false) != _ENUM_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static bool _is_valid(const char *name)
|
constexpr static bool is_valid(const char *name)
|
||||||
{
|
{
|
||||||
return _from_string_loop(name, false) != _ENUM_NOT_FOUND;
|
return _from_string_loop(name, false) != _ENUM_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static bool _is_valid_nocase(const char *name)
|
constexpr static bool is_valid_nocase(const char *name)
|
||||||
{
|
{
|
||||||
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; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
_Enumerated _value;
|
|
||||||
|
|
||||||
static const char * const *_processedNames;
|
static const char * const *_processedNames;
|
||||||
|
|
||||||
static void _processNames()
|
static void _processNames()
|
||||||
{
|
{
|
||||||
if (_processedNames == nullptr)
|
if (_processedNames == nullptr)
|
||||||
_processedNames = _enum::_processNames(_name_array, _size);
|
_processedNames = _enum::_processNames(_name_array, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* _getProcessedName(size_t index)
|
static const char* _getProcessedName(size_t index)
|
||||||
@ -516,28 +511,30 @@ class _Enum : public _GeneratedArrays<Tag> {
|
|||||||
return _processedNames[index];
|
return _processedNames[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
using _ValueIterable = _Iterable<_Enum, _ValueIterator<_Enum>>;
|
using _ValueIterable =
|
||||||
using _NameIterable = _Iterable<_Enum, _NameIterator<_Enum>>;
|
_enum::_Iterable<traits, _enum::_ValueIterator<traits>>;
|
||||||
|
using _NameIterable =
|
||||||
|
_enum::_Iterable<traits, _enum::_NameIterator<traits>>;
|
||||||
|
|
||||||
friend _ValueIterator<_Enum>;
|
friend _enum::_ValueIterator<traits>;
|
||||||
friend _NameIterator<_Enum>;
|
friend _enum::_NameIterator<traits>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const _ValueIterable _values;
|
static const _ValueIterable values;
|
||||||
static const _NameIterable _names;
|
static const _NameIterable names;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
constexpr static size_t _from_int_loop(_Integral value,
|
constexpr static size_t _from_int_loop(Integral value,
|
||||||
bool throw_exception,
|
bool throw_exception,
|
||||||
size_t index = 0)
|
size_t index = 0)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
index == _size ?
|
index == size ?
|
||||||
(throw_exception ?
|
(throw_exception ?
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Enum::_from_integral: invalid integer value") :
|
"enum_::traits::from_integral: invalid integer value") :
|
||||||
_ENUM_NOT_FOUND) :
|
_ENUM_NOT_FOUND) :
|
||||||
_value_array[index] == value ? index :
|
(Integral)_value_array[index] == value ? index :
|
||||||
_from_int_loop(value, throw_exception, index + 1);
|
_from_int_loop(value, throw_exception, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,12 +543,12 @@ class _Enum : public _GeneratedArrays<Tag> {
|
|||||||
size_t index = 0)
|
size_t index = 0)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
index == _size ?
|
index == size ?
|
||||||
(throw_exception ?
|
(throw_exception ?
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Enum::_from_string: invalid string argument") :
|
"enum_::traits::from_string: invalid string argument") :
|
||||||
_ENUM_NOT_FOUND) :
|
_ENUM_NOT_FOUND) :
|
||||||
_namesMatch(_name_array[index], name) ? index :
|
_enum::_namesMatch(_name_array[index], name) ? index :
|
||||||
_from_string_loop(name, throw_exception, index + 1);
|
_from_string_loop(name, throw_exception, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,98 +557,78 @@ class _Enum : public _GeneratedArrays<Tag> {
|
|||||||
size_t index = 0)
|
size_t index = 0)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
index == _size ?
|
index == size ?
|
||||||
(throw_exception ?
|
(throw_exception ?
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Enum::_from_string_nocase: invalid string argument") :
|
"enum::traits::_from_string_nocase: "
|
||||||
|
"invalid string argument") :
|
||||||
_ENUM_NOT_FOUND) :
|
_ENUM_NOT_FOUND) :
|
||||||
_namesMatchNocase(_name_array[index], name) ? index :
|
_enum::_namesMatchNocase(_name_array[index], name) ? index :
|
||||||
_from_string_nocase_loop(name, throw_exception, index + 1);
|
_from_string_nocase_loop(name, throw_exception, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr bool operator ==(const _Enum &other) const
|
|
||||||
{ return _value == other._value; }
|
|
||||||
constexpr bool operator ==(const _Enumerated value) const
|
|
||||||
{ return _value == value; }
|
|
||||||
template <typename T> bool operator ==(T other) const = delete;
|
|
||||||
|
|
||||||
constexpr bool operator !=(const _Enum &other) const
|
|
||||||
{ return !(*this == other); }
|
|
||||||
constexpr bool operator !=(const _Enumerated value) const
|
|
||||||
{ return !(*this == value); }
|
|
||||||
template <typename T> bool operator !=(T other) const = delete;
|
|
||||||
|
|
||||||
constexpr bool operator <(const _Enum &other) const
|
|
||||||
{ return _value < other._value; }
|
|
||||||
constexpr bool operator <(const _Enumerated value) const
|
|
||||||
{ return _value < value; }
|
|
||||||
template <typename T> bool operator <(T other) const = delete;
|
|
||||||
|
|
||||||
constexpr bool operator <=(const _Enum &other) const
|
|
||||||
{ return _value <= other._value; }
|
|
||||||
constexpr bool operator <=(const _Enumerated value) const
|
|
||||||
{ return _value <= value; }
|
|
||||||
template <typename T> bool operator <=(T other) const = delete;
|
|
||||||
|
|
||||||
constexpr bool operator >(const _Enum &other) const
|
|
||||||
{ return _value > other._value; }
|
|
||||||
constexpr bool operator >(const _Enumerated value) const
|
|
||||||
{ return _value > value; }
|
|
||||||
template <typename T> bool operator >(T other) const = delete;
|
|
||||||
|
|
||||||
constexpr bool operator >=(const _Enum &other) const
|
|
||||||
{ return _value >= other._value; }
|
|
||||||
constexpr bool operator >=(const _Enumerated value) const
|
|
||||||
{ return _value >= value; }
|
|
||||||
template <typename T> bool operator >=(T other) const = delete;
|
|
||||||
|
|
||||||
int operator -() const = delete;
|
|
||||||
template <typename T> int operator +(T other) const = delete;
|
|
||||||
template <typename T> int operator -(T other) const = delete;
|
|
||||||
template <typename T> int operator *(T other) const = delete;
|
|
||||||
template <typename T> int operator /(T other) const = delete;
|
|
||||||
template <typename T> int operator %(T other) const = delete;
|
|
||||||
|
|
||||||
template <typename T> int operator <<(T other) const = delete;
|
|
||||||
template <typename T> int operator >>(T other) const = delete;
|
|
||||||
|
|
||||||
int operator ~() const = delete;
|
|
||||||
template <typename T> int operator &(T other) const = delete;
|
|
||||||
template <typename T> int operator |(T other) const = delete;
|
|
||||||
template <typename T> int operator ^(T other) const = delete;
|
|
||||||
|
|
||||||
int operator !() const = delete;
|
|
||||||
template <typename T> int operator &&(T other) const = delete;
|
|
||||||
template <typename T> int operator ||(T other) const = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define _ENUM_GLOBALS(EnumType, Tag) \
|
template <typename Enum>
|
||||||
|
constexpr typename traits<Enum>::Integral to_integral(Enum value)
|
||||||
|
{
|
||||||
|
return traits<Enum>::to_integral(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
constexpr Enum from_integral(typename traits<Enum>::Integral value)
|
||||||
|
{
|
||||||
|
return traits<Enum>::from_integral(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
constexpr Enum from_integral_unchecked(typename traits<Enum>::Integral value)
|
||||||
|
{
|
||||||
|
return traits<Enum>::from_integral_unchecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
const char* to_string(Enum value)
|
||||||
|
{
|
||||||
|
return traits<Enum>::to_string(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
constexpr Enum from_string(const char *name)
|
||||||
|
{
|
||||||
|
return traits<Enum>::from_string(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Enum>
|
||||||
|
constexpr Enum from_string_nocase(const char *name)
|
||||||
|
{
|
||||||
|
return traits<Enum>::from_string_nocase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace enum_
|
||||||
|
|
||||||
|
#define _ENUM_GLOBALS(EnumType) \
|
||||||
namespace _enum { \
|
namespace _enum { \
|
||||||
\
|
\
|
||||||
constexpr const EnumType operator +(EnumType::_Enumerated enumerated) \
|
constexpr _GeneratedArrays<EnumType>::Enumerated _ENUM_WEAK \
|
||||||
{ return (EnumType)enumerated; } \
|
_GeneratedArrays<EnumType>::_value_array[]; \
|
||||||
|
\
|
||||||
|
constexpr const char * _ENUM_WEAK \
|
||||||
|
_GeneratedArrays<EnumType>::_name_array[]; \
|
||||||
|
\
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
template <> \
|
template <> \
|
||||||
constexpr EnumType::_ValueIterable _ENUM_WEAK EnumType::_values{}; \
|
constexpr enum_::traits<EnumType>::_ValueIterable _ENUM_WEAK \
|
||||||
|
enum_::traits<EnumType>::values{}; \
|
||||||
\
|
\
|
||||||
template <> \
|
template <> \
|
||||||
constexpr EnumType::_NameIterable _ENUM_WEAK EnumType::_names{}; \
|
constexpr enum_::traits<EnumType>::_NameIterable _ENUM_WEAK \
|
||||||
\
|
enum_::traits<EnumType>::names{}; \
|
||||||
constexpr _GeneratedArrays<Tag>::_Enumerated _ENUM_WEAK \
|
|
||||||
_GeneratedArrays<Tag>::_value_array[]; \
|
|
||||||
\
|
|
||||||
constexpr const char * _ENUM_WEAK _GeneratedArrays<Tag>::_name_array[]; \
|
|
||||||
\
|
\
|
||||||
template <> \
|
template <> \
|
||||||
const char * const * _ENUM_WEAK EnumType::_processedNames = nullptr; \
|
const char * const * _ENUM_WEAK enum_::traits<EnumType>::_processedNames = \
|
||||||
\
|
nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace _enum
|
|
||||||
|
|
||||||
#define ENUM(EnumType, Integral, ...) \
|
#define ENUM(EnumType, Integral, ...) \
|
||||||
_ENUM_TAG_DECLARATION(EnumType); \
|
_ENUM_ARRAYS(EnumType, Integral, __VA_ARGS__); \
|
||||||
_ENUM_ARRAYS(EnumType, Integral, _ENUM_TAG(EnumType), __VA_ARGS__); \
|
_ENUM_GLOBALS(EnumType);
|
||||||
using EnumType = _enum::_Enum<_enum::_ENUM_TAG(EnumType)>; \
|
|
||||||
_ENUM_GLOBALS(EnumType, _ENUM_TAG(EnumType));
|
|
||||||
|
|||||||
@ -3,15 +3,16 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <enum.h>
|
#include <enum.h>
|
||||||
|
|
||||||
ENUM(Channel, uint8_t, Red, Green = 2, Blue, Alias = Red);
|
ENUM(Channel, uint8_t, Red, Green = 2, Blue, Alias = Channel::Red);
|
||||||
|
|
||||||
void print_channel(Channel channel)
|
void print_channel(Channel channel)
|
||||||
{
|
{
|
||||||
std::cout
|
std::cout
|
||||||
<< "channel \'"
|
<< "channel \'"
|
||||||
<< channel.to_string()
|
<< enum_::to_string(channel)
|
||||||
<< "\' has value "
|
<< "\' has value "
|
||||||
<< (int)channel.to_integral() << std::endl;
|
<< enum_::to_integral(channel)
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@ -28,32 +29,32 @@ int main()
|
|||||||
// Conversions from strings and the integral type. Function names are
|
// Conversions from strings and the integral type. Function names are
|
||||||
// prefixed with _ to avoid conflicts with constant names. _from_integral is
|
// prefixed with _ to avoid conflicts with constant names. _from_integral is
|
||||||
// a checked cast.
|
// a checked cast.
|
||||||
channel = Channel::_from_integral(0);
|
channel = enum_::from_integral<Channel>(0);
|
||||||
print_channel(channel);
|
print_channel(channel);
|
||||||
|
|
||||||
channel = Channel::_from_string("Blue");
|
channel = enum_::from_string<Channel>("Blue");
|
||||||
print_channel(channel);
|
print_channel(channel);
|
||||||
|
|
||||||
channel = Channel::_from_string_nocase("bluE");
|
channel = enum_::from_string_nocase<Channel>("bluE");
|
||||||
print_channel(channel);
|
print_channel(channel);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Bad conversions.
|
// Bad conversions.
|
||||||
try {
|
try {
|
||||||
channel = Channel::_from_integral(15);
|
channel = enum_::from_integral<Channel>(15);
|
||||||
throw std::logic_error("expected an exception");
|
throw std::logic_error("expected an exception");
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error &e) { }
|
catch (const std::runtime_error &e) { }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel = Channel::_from_string("Purple");
|
channel = enum_::from_string<Channel>("Purple");
|
||||||
throw std::logic_error("expected an exception");
|
throw std::logic_error("expected an exception");
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error &e) { }
|
catch (const std::runtime_error &e) { }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel = Channel::_from_string_nocase("bluee");
|
channel = enum_::from_string_nocase<Channel>("bluee");
|
||||||
throw std::logic_error("expected an exception");
|
throw std::logic_error("expected an exception");
|
||||||
}
|
}
|
||||||
catch (const std::runtime_error &e) { }
|
catch (const std::runtime_error &e) { }
|
||||||
@ -61,29 +62,23 @@ int main()
|
|||||||
|
|
||||||
|
|
||||||
// Unsafe unchecked cast.
|
// Unsafe unchecked cast.
|
||||||
channel = Channel::_from_integral_unchecked(2);
|
channel = enum_::from_integral_unchecked<Channel>(2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Direct conversion of a constant unfortunately requires an explicit
|
// Direct conversion of a constant unfortunately requires an explicit
|
||||||
// promotion.
|
// promotion.
|
||||||
std::cout << (+Channel::Green).to_string() << std::endl;
|
std::cout << enum_::to_string(Channel::Green) << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The type name is available as a string.
|
// The type name is available as a string.
|
||||||
std::cout << Channel::_name << std::endl;
|
std::cout << enum_::traits<Channel>::name << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(sizeof(Channel) == sizeof(uint8_t),
|
static_assert(std::is_same<enum_::traits<Channel>::Integral, uint8_t>(),
|
||||||
"enum has the same size as its underlying integral type");
|
|
||||||
|
|
||||||
static_assert(alignof(Channel) == alignof(uint8_t),
|
|
||||||
"enum has the same alignment as its underlying integral type");
|
|
||||||
|
|
||||||
static_assert(std::is_same<Channel::_Integral, uint8_t>(),
|
|
||||||
"the underlying integral type is accessible as a member");
|
"the underlying integral type is accessible as a member");
|
||||||
|
|||||||
@ -8,22 +8,26 @@ ENUM(Channel, int, Red = 3, Green = 4, Blue = 0);
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
// Static range properties.
|
// Static range properties.
|
||||||
std::cout << "first: " << (+Channel::_first).to_string() << std::endl;
|
std::cout << "first: " <<
|
||||||
std::cout << "last: " << (+Channel::_last).to_string() << std::endl;
|
enum_::to_string(enum_::traits<Channel>::first) << std::endl;
|
||||||
std::cout << "minimum: " << (+Channel::_min).to_string() << std::endl;
|
std::cout << "last: " <<
|
||||||
std::cout << "maximum: " << (+Channel::_max).to_string() << std::endl;
|
enum_::to_string(enum_::traits<Channel>::last) << std::endl;
|
||||||
std::cout << "count: " << Channel::_size << std::endl;
|
std::cout << "minimum: " <<
|
||||||
std::cout << "span: " << Channel::_span << std::endl;
|
enum_::to_string(enum_::traits<Channel>::min) << std::endl;
|
||||||
|
std::cout << "maximum: " <<
|
||||||
|
enum_::to_string(enum_::traits<Channel>::max) << std::endl;
|
||||||
|
std::cout << "count: " << enum_::traits<Channel>::size << std::endl;
|
||||||
|
std::cout << "span: " << enum_::traits<Channel>::span << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Listing declared values.
|
// Listing declared values.
|
||||||
for (Channel channel : Channel::_values)
|
for (Channel channel : enum_::traits<Channel>::values)
|
||||||
std::cout << channel.to_integral() << " ";
|
std::cout << enum_::to_integral(channel) << " ";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
// Listing declared names.
|
// Listing declared names.
|
||||||
for (const char *name : Channel::_names)
|
for (const char *name : enum_::traits<Channel>::names)
|
||||||
std::cout << name << " ";
|
std::cout << name << " ";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
@ -32,7 +36,7 @@ int main()
|
|||||||
// Direct iterator usage.
|
// Direct iterator usage.
|
||||||
std::cout
|
std::cout
|
||||||
<< "first (using iterator): "
|
<< "first (using iterator): "
|
||||||
<< *Channel::_names.begin()
|
<< *enum_::traits<Channel>::names.begin()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -10,37 +10,40 @@ ENUM(Channel, int, Red, Green, Blue);
|
|||||||
// Initialization.
|
// Initialization.
|
||||||
constexpr Channel channel_1 = Channel::Green;
|
constexpr Channel channel_1 = Channel::Green;
|
||||||
|
|
||||||
constexpr Channel channel_4 = Channel::_from_integral(2);
|
constexpr Channel channel_4 = enum_::from_integral<Channel>(2);
|
||||||
|
|
||||||
constexpr Channel channel_2 = Channel::_from_string("Blue");
|
constexpr Channel channel_2 = enum_::from_string<Channel>("Blue");
|
||||||
constexpr Channel channel_3 = Channel::_from_string_nocase("gReEn");
|
constexpr Channel channel_3 = enum_::from_string_nocase<Channel>("gReEn");
|
||||||
|
|
||||||
// Conversion to integer (but not to string).
|
// Conversion to integer (but not to string).
|
||||||
constexpr int channel_1_representation = channel_1.to_integral();
|
constexpr int channel_1_representation = enum_::to_integral(channel_1);
|
||||||
|
|
||||||
// Validity checks (including against strings).
|
// Validity checks (including against strings).
|
||||||
constexpr bool should_be_valid_1 = Channel::_is_valid(2);
|
constexpr bool should_be_valid_1 = enum_::traits<Channel>::is_valid(2);
|
||||||
constexpr bool should_be_invalid_1 = Channel::_is_valid(42);
|
constexpr bool should_be_invalid_1 = enum_::traits<Channel>::is_valid(42);
|
||||||
|
|
||||||
constexpr bool should_be_valid_2 = Channel::_is_valid("Red");
|
constexpr bool should_be_valid_2 = enum_::traits<Channel>::is_valid("Red");
|
||||||
constexpr bool should_be_invalid_2 = Channel::_is_valid("red");
|
constexpr bool should_be_invalid_2 =
|
||||||
|
enum_::traits<Channel>::is_valid("red");
|
||||||
|
|
||||||
constexpr bool should_be_valid_3 = Channel::_is_valid_nocase("red");
|
constexpr bool should_be_valid_3 =
|
||||||
constexpr bool should_be_invalid_3 = Channel::_is_valid_nocase("reed");
|
enum_::traits<Channel>::is_valid_nocase("red");
|
||||||
|
constexpr bool should_be_invalid_3 =
|
||||||
|
enum_::traits<Channel>::is_valid_nocase("reed");
|
||||||
|
|
||||||
// _names and _values collections and iterator creation.
|
// _names and _values collections and iterator creation.
|
||||||
constexpr Channel channel_5 = *Channel::_values.begin();
|
constexpr Channel channel_5 = *enum_::traits<Channel>::values.begin();
|
||||||
constexpr auto name_iterator = Channel::_names.begin();
|
constexpr auto name_iterator = enum_::traits<Channel>::names.begin();
|
||||||
|
|
||||||
// Range properties.
|
// Range properties.
|
||||||
constexpr Channel channel_6 = Channel::_max;
|
constexpr Channel channel_6 = enum_::traits<Channel>::max;
|
||||||
constexpr size_t span = Channel::_span;
|
constexpr size_t span = enum_::traits<Channel>::span;
|
||||||
|
|
||||||
// Type name.
|
// Type name.
|
||||||
constexpr auto name = Channel::_name;
|
constexpr auto name = enum_::traits<Channel>::name;
|
||||||
|
|
||||||
// Explicit promotion.
|
// Explicit promotion.
|
||||||
constexpr int converted = (+Channel::Green).to_integral();
|
constexpr int converted = enum_::to_integral(Channel::Green);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +54,7 @@ void print_channel(int number, Channel channel)
|
|||||||
<< "channel_"
|
<< "channel_"
|
||||||
<< number
|
<< number
|
||||||
<< " is "
|
<< " is "
|
||||||
<< channel.to_string()
|
<< enum_::to_string(channel)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ int main()
|
|||||||
vector.push_back(Channel::Red);
|
vector.push_back(Channel::Red);
|
||||||
|
|
||||||
for (Channel channel : vector)
|
for (Channel channel : vector)
|
||||||
std::cout << channel.to_string() << " ";
|
std::cout << enum_::to_string(channel) << " ";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ int main()
|
|||||||
std::map<const char*, Channel> map = {{"first", Channel::Blue}};
|
std::map<const char*, Channel> map = {{"first", Channel::Blue}};
|
||||||
map.insert({"second", Channel::Green});
|
map.insert({"second", Channel::Green});
|
||||||
|
|
||||||
for (Channel channel : Channel::_values)
|
for (Channel channel : enum_::traits<Channel>::values)
|
||||||
map.insert({channel.to_string(), channel});
|
map.insert({enum_::to_string(channel), channel});
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto item : map) {
|
for (auto item : map) {
|
||||||
@ -43,7 +43,7 @@ int main()
|
|||||||
std::cout
|
std::cout
|
||||||
<< item.first
|
<< item.first
|
||||||
<< " -> "
|
<< " -> "
|
||||||
<< item.second.to_string();
|
<< enum_::to_string(item.second);
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
constexpr const Enum default_()
|
constexpr const Enum default_()
|
||||||
{
|
{
|
||||||
return Enum::_first;
|
return enum_::traits<Enum>::first;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make it possible to override the convention for specific enums.
|
// Make it possible to override the convention for specific enums.
|
||||||
@ -35,10 +35,10 @@ int main()
|
|||||||
// default value is still declared in one place, not all over the program
|
// default value is still declared in one place, not all over the program
|
||||||
// code.
|
// code.
|
||||||
Depth depth = default_<Depth>();
|
Depth depth = default_<Depth>();
|
||||||
std::cout << depth.to_string() << std::endl;
|
std::cout << enum_::to_string(depth) << std::endl;
|
||||||
|
|
||||||
std::cout << default_<Channel>().to_string() << std::endl;
|
std::cout << enum_::to_string(default_<Channel>()) << std::endl;
|
||||||
std::cout << default_<Depth>().to_string() << std::endl;
|
std::cout << enum_::to_string(default_<Depth>()) << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user