Changed _size to a function.

An alternative constant _size_constant is provided for use in C++98,
for example for declaring arrays.

Also renamed underlying_traits to integral_mapping.
This commit is contained in:
Anton Bachin 2015-06-19 14:01:58 -05:00
parent aa34aad468
commit 9810dd07ce
12 changed files with 43 additions and 39 deletions

View File

@ -71,7 +71,7 @@ slightly more complex template function for the general case:
constexpr <em>Enum default_imp</em>l()
{
return
<em>Enum::_size < 2 ?
<em>Enum::_size() < 2 ?
throw std::logic_error("enum has no valid constants") :
Enum::_values()[0] == invalid_impl<Enum>() ?
Enum::_values()[1] :

View File

@ -17,7 +17,7 @@ We simply need to find the maximum value of any given enum type.
constexpr <em>Enum max_loop</em>(Enum accumulator, size_t index)
{
return
<em>index >= Enum::_size ? accumulator :
<em>index >= Enum::_size() ? accumulator :
Enum::_values()[index] > accumulator ?
max_loop<Enum>(Enum::_values()[index], index + 1) :
max_loop<Enum>(accumulator, index + 1)</em>;

View File

@ -82,7 +82,7 @@ initializers for sequential values, but I won't go through this exercise here.
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
{
return
<em>index >= Enum::_size ? accumulator :
<em>index >= Enum::_size() ? accumulator :
constants_length<Enum>(
index + 1, accumulator
+ string_length(", ")

View File

@ -11,7 +11,7 @@ example, this:
int main()
{
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
Channel channel = <em>Channel::_values()[index]</em>;
std::cout << channel._to_integral() << " ";
}
@ -19,7 +19,7 @@ example, this:
will print "0 2 3". And this:
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
const char *name = <em>Channel::_names()[index]</em>;
std::cout << name << " ";
}

45
enum.h
View File

@ -499,7 +499,7 @@ template <> struct _representation<char32_t> { typedef char32_t type; };
#endif
template <typename T>
struct underlying_traits {
struct integral_mapping {
typedef typename _representation<T>::type integral_representation;
BETTER_ENUMS__CONSTEXPR static integral_representation
@ -620,20 +620,20 @@ class Enum { \
private: \
typedef ::better_enums::optional<Enum> _optional; \
typedef ::better_enums::optional<std::size_t> _optional_index; \
typedef ::better_enums::underlying_traits<Underlying> _traits; \
typedef ::better_enums::integral_mapping<Underlying> _mapping; \
\
public: \
typedef Underlying _underlying; \
typedef _traits::integral_representation _integral; \
typedef _mapping::integral_representation _integral; \
\
enum _enumerated SetUnderlyingType(Underlying) { __VA_ARGS__ }; \
\
BETTER_ENUMS__CONSTEXPR Enum(_enumerated value) : \
_value(_traits::from_integral(value)) { } \
_value(_mapping::from_integral(value)) { } \
\
BETTER_ENUMS__CONSTEXPR operator SwitchType(Enum)() const \
{ \
return (SwitchType(Enum))_traits::to_integral(_value); \
return (SwitchType(Enum))_mapping::to_integral(_value); \
} \
\
_underlying& operator *() { return _value; } \
@ -689,8 +689,10 @@ class Enum { \
typedef _value_iterable::iterator _value_iterator; \
typedef _name_iterable::iterator _name_iterator; \
\
BETTER_ENUMS__CONSTEXPR static const std::size_t _size = \
BETTER_ENUMS__CONSTEXPR static const std::size_t _size_constant = \
BETTER_ENUMS__ID(BETTER_ENUMS__PP_COUNT(__VA_ARGS__)); \
BETTER_ENUMS__CONSTEXPR static std::size_t _size() \
{ return _size_constant; } \
\
BETTER_ENUMS__CONSTEXPR static const char* _name(); \
BETTER_ENUMS__CONSTEXPR static _value_iterable _values(); \
@ -699,7 +701,7 @@ class Enum { \
_underlying _value; \
\
private: \
Enum() : _value(_traits::from_integral(0)) { } \
Enum() : _value(_mapping::from_integral(0)) { } \
\
explicit BETTER_ENUMS__CONSTEXPR Enum(const _underlying &value) : \
_value(value) { } \
@ -765,7 +767,7 @@ Enum::_from_underlying_nothrow(const _underlying &value) \
\
BETTER_ENUMS__CONSTEXPR inline Enum::_integral Enum::_to_integral() const \
{ \
return _traits::to_integral(_value); \
return _mapping::to_integral(_value); \
} \
\
BETTER_ENUMS__CONSTEXPR inline Enum \
@ -786,7 +788,7 @@ BETTER_ENUMS__CONSTEXPR inline Enum Enum::_from_integral(_integral value) \
BETTER_ENUMS__CONSTEXPR inline Enum::_optional \
Enum::_from_integral_nothrow(_integral value) \
{ \
return _from_underlying_nothrow(_traits::from_integral(value)); \
return _from_underlying_nothrow(_mapping::from_integral(value)); \
} \
\
ToStringConstexpr inline const char* Enum::_to_string() const \
@ -855,14 +857,14 @@ BETTER_ENUMS__CONSTEXPR inline const char* Enum::_name() \
\
BETTER_ENUMS__CONSTEXPR inline Enum::_value_iterable Enum::_values() \
{ \
return _value_iterable(BETTER_ENUMS__NS(Enum)::value_array, _size); \
return _value_iterable(BETTER_ENUMS__NS(Enum)::value_array, _size()); \
} \
\
ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
{ \
return \
_name_iterable(BETTER_ENUMS__NS(Enum)::name_array(), \
CallInitialize(_size)); \
CallInitialize(_size())); \
} \
\
DefineInitialize(Enum) \
@ -871,9 +873,10 @@ BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
Enum::_from_value_loop(const Enum::_underlying &value, std::size_t index) \
{ \
return \
index == _size ? _optional_index() : \
_traits::to_integral(BETTER_ENUMS__NS(Enum)::value_array[index]._value)\
== _traits::to_integral(value) ? _optional_index(index) : \
index == _size() ? _optional_index() : \
_mapping::to_integral( \
BETTER_ENUMS__NS(Enum)::value_array[index]._value) \
== _mapping::to_integral(value) ? _optional_index(index) : \
_from_value_loop(value, index + 1); \
} \
\
@ -881,7 +884,7 @@ BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
Enum::_from_string_loop(const char *name, std::size_t index) \
{ \
return \
index == _size ? _optional_index() : \
index == _size() ? _optional_index() : \
::better_enums::_names_match( \
BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \
_optional_index(index) : \
@ -892,7 +895,7 @@ BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
Enum::_from_string_nocase_loop(const char *name, std::size_t index) \
{ \
return \
index == _size ? _optional_index() : \
index == _size() ? _optional_index() : \
::better_enums::_names_match_nocase( \
BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \
_optional_index(index) : \
@ -921,7 +924,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
// C++11
#define BETTER_ENUMS__CXX11_UNDERLYING_TYPE(Underlying) \
: ::better_enums::underlying_traits<Underlying>::integral_representation
: ::better_enums::integral_mapping<Underlying>::integral_representation
// C++98, C++11
#define BETTER_ENUMS__REGULAR_ENUM_SWITCH_TYPE(Type) \
@ -937,7 +940,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
// C++11
#define BETTER_ENUMS__ENUM_CLASS_SWITCH_TYPE_GENERATE(Underlying, ...) \
enum class EnumClassForSwitchStatements : \
::better_enums::underlying_traits<Underlying>::integral_representation \
::better_enums::integral_mapping<Underlying>::integral_representation \
{ __VA_ARGS__ };
// C++98
@ -958,7 +961,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
\
inline const char** name_array() \
{ \
static const char *value[Enum::_size]; \
static const char *value[Enum::_size_constant]; \
return value; \
} \
\
@ -987,7 +990,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
\
inline const char** name_array() \
{ \
static const char *value[Enum::_size]; \
static const char *value[Enum::_size_constant]; \
return value; \
} \
\
@ -1039,7 +1042,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
::better_enums::_trim_names(BETTER_ENUMS__NS(Enum)::raw_names(), \
BETTER_ENUMS__NS(Enum)::name_array(), \
BETTER_ENUMS__NS(Enum)::name_storage(), \
_size); \
_size()); \
\
BETTER_ENUMS__NS(Enum)::initialized() = true; \
\

View File

@ -69,7 +69,7 @@ template <typename Enum>
constexpr Enum default_impl()
{
return
Enum::_size < 2 ?
Enum::_size() < 2 ?
throw std::logic_error("enum has no valid constants") :
Enum::_values()[0] == invalid_impl<Enum>() ?
Enum::_values()[1] :

View File

@ -17,7 +17,7 @@ template <typename Enum>
constexpr Enum max_loop(Enum accumulator, size_t index)
{
return
index >= Enum::_size ? accumulator :
index >= Enum::_size() ? accumulator :
Enum::_values()[index] > accumulator ?
max_loop<Enum>(Enum::_values()[index], index + 1) :
max_loop<Enum>(accumulator, index + 1);

View File

@ -79,7 +79,7 @@ template <typename Enum>
constexpr size_t constants_length(size_t index = 0, size_t accumulator = 0)
{
return
index >= Enum::_size ? accumulator :
index >= Enum::_size() ? accumulator :
constants_length<Enum>(
index + 1, accumulator
+ string_length(", ")

View File

@ -13,7 +13,7 @@ ENUM(Channel, int, Red, Green = 2, Blue)
int main()
{
for (size_t index = 0; index < Channel::_size; ++index) {
for (size_t index = 0; index < Channel::_size(); ++index) {
Channel channel = Channel::_values()[index];
std::cout << channel._to_integral() << " ";
}
@ -21,7 +21,7 @@ int main()
// will print "0 2 3". And this:
for (size_t index = 0; index < Channel::_size; ++index) {
for (size_t index = 0; index < Channel::_size(); ++index) {
const char *name = Channel::_names()[index];
std::cout << name << " ";
}

View File

@ -114,7 +114,7 @@ static_assert_1(
static_assert_1(Channel::_is_valid("Green"));
static_assert_1(Channel::_is_valid_nocase("green"));
static_assert_1(Channel::_size == 3);
static_assert_1(Channel::_size() == 3);
static_assert_1(Channel::_values().size() == 3);
static_assert_1(*Channel::_values().begin() == +Channel::Red);
static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue);
@ -218,9 +218,9 @@ class EnumTests : public CxxTest::TestSuite {
void test_value_iterable()
{
TS_ASSERT_EQUALS(Channel::_size, 3);
TS_ASSERT_EQUALS(Depth::_size, 2);
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size);
TS_ASSERT_EQUALS(Channel::_size(), 3);
TS_ASSERT_EQUALS(Depth::_size(), 2);
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size());
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
@ -245,7 +245,7 @@ class EnumTests : public CxxTest::TestSuite {
void test_name_iterable()
{
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size);
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size());
TS_ASSERT_EQUALS(strcmp(*Channel::_names().begin(), "Red"), 0);
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);

View File

@ -19,11 +19,12 @@ struct html_color_1 {
r(_r), g(_g), b(_b) { }
};
// In C++11, can simply to struct ::better_enums::underlying_traits below.
// In C++11, can simply use struct ::better_enums::integral_mapping below,
// instead of having to enclose the specialization in the namespace.
namespace better_enums {
template <>
struct underlying_traits<html_color_1> {
struct integral_mapping<html_color_1> {
typedef unsigned int integral_representation;
BETTER_ENUMS__CONSTEXPR static html_color_1 from_integral(unsigned int i)

View File

@ -4,5 +4,5 @@
void print(Channel channel)
{
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
std::cout << Channel::_size << std::endl;
std::cout << Channel::_size() << std::endl;
}