diff --git a/README.md b/README.md
index a0c1b78..b765ef6 100644
--- a/README.md
+++ b/README.md
@@ -53,11 +53,9 @@ the rich enums that are missing from standard C++.
- Stream operators.
- Does not use the heap and can be compiled with exceptions disabled, for use in
minimal freestanding environments.
-- The underlying type [does not have to be an integral type][underlying].
[testing]: http://aantron.github.io/better-enums/CompilerSupport.html
[performance]: http://aantron.github.io/better-enums/Performance.html
-[underlying]: http://aantron.github.io/better-enums/demo/NonIntegralUnderlyingTypes.html
## Limitations
diff --git a/doc/ApiReference.md b/doc/ApiReference.md
index 09bade4..ce035af 100644
--- a/doc/ApiReference.md
+++ b/doc/ApiReference.md
@@ -51,15 +51,6 @@ passed by value.
All names declared in the scope of a Better Enum are prefixed with an underscore
in order to avoid conflicts with potential constant names.
-If you are using [non-integral underlying types][non-integral], you need to be
-aware of section of this reference on underlying types. However, if you are
-using a regular, integral underlying type, the type `Enum::_underlying` is the
-same `Enum::_integral`, and each of the `*_underlying` functions is the same as
-the corresponding `*_integral` function, so you can safely ignore that whole
-section.
-
-[non-integral]: ${prefix}demo/NonIntegralUnderlyingTypes.html
-
### Running example
@@ -394,136 +385,6 @@ as [`_from_string`](#_from_string). In case of failure, sets the stream's
-### Non-integral underlying type
-
-This section is relevant only if you are using an underlying type that is not
-an integral type — otherwise, `Enum::_underlying` is the same as
-`Enum::_integral`, and all the functions described here are redundant with their
-corresponding functions in the [section on integer conversions][integral].
-
-That section is written for the simple, but common case where the underlying
-type is an integral type, in order to avoid overloading users not using the
-feature described here with unnecessary generality. The information in that
-section is fully accurate for integral underlying types, but for non-integral
-underlying types this section corrects it.
-
-[integral]: #IntegerConversion
-
-The rest of this section will assume that your non-integral underlying type is
-called `Underlying`.
-
-In this case, the memory representation of your Better Enum type is the same as
-for `Underlying`. In fact, this is always true — the memory representation
-is always the same as for the underlying type. It is only a matter of whether
-that type is integral or not.
-
-When `Underlying` is not integral, Better Enums still needs an integral
-representation of `Underlying` for use in `switch`. That is the true meaning of
-the member type `_integral`. It's just that when `Underlying` *is* integral to
-begin with, it is its own integral representation, and the two types collapse.
-
-To support non-integral underlying types, Better Enums requires a two-way
-mapping between `Underlying` and some type `_integral`. In case `Underlying`
-*is* integral, however, that mapping is simply the identity function. Otherwise,
-you have to supply a mapping as shown [here][non-integral].
-
-In short, the underlying type is "first-class," whether it is integral or not,
-and the type `_integral` is a helper type. When `Underlying` *is* integral, the
-various `*_integral` functions just happen to work with the underlying type, as
-a special case. The material in this section is for the general case where
-`Underlying` is not integral.
-
-#### typename _underlying
-
-`Enum::_underlying` is the same type as `Underlying`. It has to satisfy the
-requirements given [here][non-integral].
-
-#### non-member specialization struct better_enums::integral_mapping<Underlying>
-
-You should specialize this template for `Underlying`, as shown in the
-[example][non-integral]. The specialization needs the following members:
-
-- A type `integral_representation`, which gives an integral type that Better
- Enums will use to make `Underlying` compatible with `switch` statements, and
- to define an ordering on the generated Better Enums type. This type is *not*
- the internal representation of the Better Enum — the Better Enum's
- memory representation is the same as `Underlying`.
-- A function
- `constexpr static integral_representation to_integral(const Underlying&)`.
-- A function
- `constexpr static Underlying from_integral(integral_representation)`.
-
-In $cxx98, the above functions don't have to be `constexpr`.
-
-You can avoid specializing this template, but its default implementation puts
-additional requirements on `Underlying` in order to be able to define default
-versions of `to_integral` and `from_integral`:
-
-- `Underlying` must have a member type `integral_representation`, with the same
- meaning as above.
-- `Underlying` must have a conversion
- `constexpr operator integral_representation() const`.
-- `Underlying` must have a constructor
- `constexpr Underlying(integral_representation)`. This constructor can be
- explicit.
-
-Again, in $cxx98, these members don't have to be `constexpr`.
-
-#### member constexpr _underlying _to_underlying() const
-
-No-op conversion of a Better Enum to its underlying type. Behaves as
-[`_to_integral`](#_to_integral), except that the text concerning implicit
-conversions is irrelevant when `_underlying` is not the same as `_integral`.
-Implicit conversions, if not disabled, are always to `_integral`.
-
-#### static constexpr Enum _from_underlying(_underlying)
-
-Same as [`_from_integral`](#_from_integral), but for the underlying type. In
-fact, `from_integral` is a wrapper that first converts the integer to a value of
-the underlying type (a no-op when the types are equal), and then calls
-`_from_underlying`.
-
-#### static constexpr optional _from_underlying_nothrow(_underlying)
-
-Same as [`_from_integral_nothrow`](#_from_integral_nothrow), but for the
-underlying type. `_from_integral_nothrow` is a wrapper as described
-[above](#_from_underlying).
-
-#### static constexpr Enum _from_underlying_unchecked(_underlying)
-
-Same as [`_from_integral_unchecked`](#_from_integral), but for the underlying
-type. `_from_integral_unchecked` is a wrapper as described
-[above](#_from_underlying).
-
-#### static constexpr bool _is_valid(_underlying)
-
-Replaces [`_is_valid(_integral)`](#_is_valid_integral). In fact, *this* function
-is the only one defined, but in the case where `_integral` is `_underlying`,
-this function's signature is equivalent to
-[`_is_valid(_integral)`](#_is_valid_integral).
-
-#### static constexpr _value_iterable _values — _underlying[]()
-
-Collection of declared enum values, stored in memory as instances of the
-underlying type.
-
-Replaces [`_values`](#_values), the collection of integral values of declared
-constants. In fact, this is the only member defined — in the case where
-`_integral` is the same as `_underlying`, the definition in the section on
-integer conversions is equivalent to this one.
-
-#### member constexpr const _underlying& operator *() const
-
-Returns a reference to the wrapped underlying value. There is also a non-`const`
-version.
-
-#### member constexpr const _underlying* operator ->() const
-
-Returns a pointer to the wrapped underlying value that is suitable for member
-access, if `_underlying` has members.
-
-
-
%% class = api
%% description = Detailed description of the Better Enums API.
diff --git a/doc/DesignDecisionsFAQ.md b/doc/DesignDecisionsFAQ.md
index 84808e3..eb04895 100644
--- a/doc/DesignDecisionsFAQ.md
+++ b/doc/DesignDecisionsFAQ.md
@@ -186,13 +186,6 @@ However, it also introduces some difficulties.
type, similar to how it is done [here][infer], but that will not be suitable
for all contexts, and the user may be surprised by ambiguous resolution error
messages when it is not.
-- The experimental feature presented [here][underlying] would be questionable in
- the traits interpretation. It is still possible to have a non-integral
- underlying type with traits, but it would be strange if the traits version of
- the macro accepted a non-integral underlying type, and then declared the
- actual language enum with an integral underlying type. Even though that is
- exactly what the non-traits version does, there the language enum is hidden
- inside the generated type, instead of being exposed alongside a traits type.
- Scoped constants are lost for $cxx98 unless Better Enums again wraps them in a
generated type, though it will be more lightweight than a full Better Enum of
the non-traits approach.
@@ -272,7 +265,6 @@ Choosing this approach has serious drawbacks.
[traits]: #Traits
[implicit]: ${prefix}OptInFeatures.html#StrictConversions
[infer]: ${prefix}demo/SpecialValues.html
-[underlying]: ${prefix}demo/NonIntegralUnderlyingTypes.html
[traits-branch]: $repo/tree/traits
[traits-samples]: $repo/tree/traits/samples
diff --git a/doc/GeneralUnderlyingTypes.md b/doc/GeneralUnderlyingTypes.md
deleted file mode 100644
index 9aa4e96..0000000
--- a/doc/GeneralUnderlyingTypes.md
+++ /dev/null
@@ -1,117 +0,0 @@
-## General underlying types
-
-The underlying type of a Better Enum doesn't have to be an integral type. It can
-be any literal type `T`, as long as you provide a `constexpr` two-way mapping
-between `T` and an integral type of your choosing. It also works in $cxx98,
-though, of course, `T` doesn't have to be literal and the mapping doesn't have
-to be `constexpr` — everything will be done by Better Enums at run time.
-
-Doing this enables the following usage:
-
- // The type. A color triplet.
- struct html_color {
- uint8_t r, g, b;
-
- constexpr html_color(uint8_t _r, uint8_t g, uint8_t b) :
- r(_r), g(_g), b(_b) { }
- };
-
-
-
- // The enum.
- BETTER_ENUM(Color, html_color,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954)
-
-
-
- // The usage.
- Color c = Color::darksalmon;
-
- std::cout << "Red component: " << c->r << std::endl;
-
- switch (c) {
- case Color::darksalmon: // ...
- case Color::purplemimosa: // ...
- case Color::slimegreen: // ...
- }
-
-As you can see, you can have an enumerated set of any literal type, and safely
-use the values in `switch`, with the compiler checking exhaustiveness. You can
-also access the type's members using the `enum->underlying_member` syntax.
-
-You do have to supply the mapping to an integral type, however. One option is:
-
- // The mapping. It just stuffs bits.
- template <>
- struct ::better_enums::underlying_traits {
- using integral_representation = unsigned int;
-
- constexpr static html_color from_integral(unsigned int i)
- { return html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
-
- constexpr static unsigned int to_integral(html_color c)
- { return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
- };
-
-### Using constructors in initializers
-
-The declaration above used only numeric initializers. It is possible to use the
-type's own constructors, provided the type has a `constexpr` conversion to your
-chosen integral type:
-
- // The type.
- struct html_color {
- uint8_t r, g, b;
-
- constexpr html_color(uint8_t _r, uint8_t g, uint8_t b) :
- r(_r), g(_g), b(_b) { }
-
- // This is new:
- constexpr operator unsigned int() const
- { return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }
- };
-
- // The enum.
- BETTER_ENUM(Color, html_color,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954,
- celeste = html_color(0x50, 0xeb, 0xec))
-
-This is not possible at all in $cxx98, however.
-
-### Letting the compiler enumerate your literal type
-
-You don't have to use initializers. For example, as long as your example type
-`file_descriptor` knows how to deal with the values, you can have the compiler
-generate them in sequence:
-
- BETTER_ENUM(FD, file_descriptor,
- STDIN, STDOUT, STDERR, SomePipeYourDaemonHas, ...)
-
-SAMPLE
-
-You can see the code "in action" in the [test case][test]. Be aware that it's
-not very "nice," because it uses conditional compilation to run under multiple
-compilers. I haven't written a clean sample or documentation yet simply because
-this feature is in a very early stage of development.
-
-[test]: $repo/blob/master/test/cxxtest/underlying.h
-
-### Discussion
-
-This feature is still semi-experimental, though I expect it to remain stable,
-except perhaps that I will make it possible to infer the type
-`integral_representation`.
-
-Any opinions are welcome.
-
-- The main reason Better Enums needs you to supply and explicit mapping is
- because it can't just get the "bits" of objects of underlying type in
- `constexpr` code. Both `reinterpret_cast` and union abuse seem to be forbidden
- in `constexpr` functions.
-- There is currently no way to have two different integral representaitons for
- the same underlying type in different enums. I don't think that's a major use
- case at this point, however.
-
-%% description = "Using Better Enums with non-integral underlying types."
diff --git a/doc/demo/102-any-underlying.md b/doc/demo/102-any-underlying.md
deleted file mode 100644
index 3ea68c6..0000000
--- a/doc/demo/102-any-underlying.md
+++ /dev/null
@@ -1,172 +0,0 @@
-## Non-integral underlying types
-
-The underlying type of a Better Enum doesn't have to be an integral type. It can
-be any literal type `T`, as long as you provide a `constexpr` two-way mapping
-between `T` and an integral type of your choosing. This also works in $cxx98
-— though then, of course, `T` doesn't have to be literal and the mapping
-doesn't have to be `constexpr`. In $cxx98, everything involving `T` will simply
-be done by Better Enums at run time.
-
-This feature is semi-experimental. I am considering relaxing the requirements on
-`T` so that it doesn't have to be literal. I can use a `reinterpret_cast` to
-make a mapping automatically. This will make non-integral underlying types
-easier to use, but will also prevent usage at compile time, which unfortunately
-has structural consequences for the implementation of Better Enums, and
-additional semantic consequences for usage, even at run time.
-
-In the meantime, here's how to have a non-integral underlying type in the
-current version.
-
- #include
- #include
- typedef unsigned char uint8_t; // not in C++98.
-
-
-
- // The underlying type. A color triplet.
- struct html_color {
- uint8_t r, g, b;
-
- constexpr html_color(uint8_t _r, uint8_t _g, uint8_t _b) :
- r(_r), g(_g), b(_b) { }
- };
-
- // The mapping. It just stuffs bits to get the same effect as
- // reinterpret_cast, except reinterpret_cast is not available in constexpr
- // functions, so we have to write the bit manipulations out. On modern
- // C++11 compilers, you don't have to enter the better_enums namespace like
- // this - you can just do
- // struct ::better_enums::integral_mapping { ...
- namespace better_enums {
-
- template <>
- struct integral_mapping {
- using integral_representation = unsigned int;
-
- constexpr static html_color from_integral(unsigned int i)
- { return html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
-
- constexpr static unsigned int to_integral(html_color c)
- { return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
- };
-
- }
-
-
-
- // The enum itself.
- BETTER_ENUM(Color, html_color,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954)
-
-Now, we can do:
-
- int main()
- {
- Color color = Color::darksalmon;
-
- std::cout << std::hex;
- std::cout << "Red component: " << (int)color->r << std::endl;
- std::cout << "Green component: " << (int)color->g << std::endl;
- std::cout << "Blue component: " << (int)color->b << std::endl;
-
- std::cout << color._to_string() << std::endl;
-
- switch (color) {
- case Color::darksalmon: return 0;
- case Color::purplemimosa: return 1;
- case Color::slimegreen: return 2;
- }
-
- return 0;
- }
-
-This prints each component, the name of the color (`"darksalmon"`), and then
-exits from the `switch` with status 0.
-
-### Constructors in initializers
-
-The above declaration used only numbers in initializers, but it is actually
-possible to use constructors of `html_color`. We have to add a `constexpr`
-converting operator directly to `html_color`, however:
-
-~~~comment
-struct better_html_color {
- uint8_t r, g, b;
-
- constexpr better_html_color(uint8_t _r, uint8_t _g, uint8_t _b) :
- r(_r), g(_g), b(_b) { }
-
- // This is new:
- constexpr operator unsigned int() const
- { return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }
-};
-
-namespace better_enums {
-
-template <>
-struct integral_mapping {
- using integral_representation = unsigned int;
-
- constexpr static better_html_color from_integral(unsigned int i)
- {
- return better_html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff);
- }
-
- constexpr static unsigned int to_integral(better_html_color c)
- { return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
-};
-
-}
-~~~
-
-This allows:
-
-~~~comment
-BETTER_ENUM(BetterColor, better_html_color,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954,
- celeste = better_html_color(0x50, 0xeb, 0xec))
-~~~
-
-If you can't edit your literal type to add this converting operator, or don't
-want to for type safety reasons, you can achieve a similar effect by declaring
-an intermediate type `U` that `html_color` can convert to, that can convert to
-the integral type. Then, cast your constructor call to `U`. The type `U` is for
-declarations only.
-
-Constructors in initializers require $cxx11. Also, g++ doesn't support this
-before 5.1.
-
-### Letting the compiler enumerate your type
-
-Of course, as long as the values are valid, you can let the compiler enumerate
-your type as in a regular enum, by omitting initializers:
-
-~~~comment
-BETTER_ENUM(FD, file_descriptor,
- STDIN, STDOUT, STDERR, SomePipeYourDaemonHas, ...)
-~~~
-
-Here, `FD::STDIN` maps to the integral representation 0, `STDOUT` to 1, and so
-on.
-
-### Discussion
-
-This feature is still semi-experimental, though I expect it to remain stable,
-except perhaps that I will make it possible to infer the type
-`integral_representation`.
-
-Any opinions are welcome.
-
-- The main reason Better Enums needs you to supply and explicit mapping is
- because it can't just get the "bits" of objects of underlying type in
- `constexpr` code. Both `reinterpret_cast` and union abuse seem to be forbidden
- in `constexpr` functions.
-- There is currently no way to have two different integral representaitons for
- the same underlying type in different enums. I don't think that's a major use
- case at this point, however.
-
-
-
-%% description = "Using Better Enums with non-integral underlying types."
diff --git a/doc/index.md b/doc/index.md
index 3c3d68c..01f671d 100644
--- a/doc/index.md
+++ b/doc/index.md
@@ -163,14 +163,6 @@ Try it live online in
- Non-integral underlying types
-
- Have sets of named, switch-friendly constants of any literal
- type.
-
-
-
-
Free and open source
Released under the BSD license for use in any project, free or commercial.
diff --git a/enum.h b/enum.h
index 66856f4..0ba3ad4 100644
--- a/enum.h
+++ b/enum.h
@@ -25,21 +25,11 @@
# if !defined(__EXCEPTIONS) || !__has_feature(cxx_exceptions)
# define BETTER_ENUMS__NO_EXCEPTIONS
# endif
-# if __cplusplus >= 201103L
-# define BETTER_ENUMS__HAVE_LONG_LONG
-# define BETTER_ENUMS__HAVE_NEW_CHAR_TYPES
-# endif
# else
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
# define BETTER_ENUMS__HAVE_CONSTEXPR
# endif
-# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))
-# define BETTER_ENUMS__HAVE_LONG_LONG
-# endif
-# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4))
-# define BETTER_ENUMS__HAVE_NEW_CHAR_TYPES
-# endif
# endif
# ifndef __EXCEPTIONS
# define BETTER_ENUMS__NO_EXCEPTIONS
@@ -48,9 +38,6 @@
#endif
#ifdef _MSC_VER
-# if _MSC_VER >= 1600
-# define BETTER_ENUMS__HAVE_LONG_LONG
-# endif
# ifndef _CPPUNWIND
# define BETTER_ENUMS__NO_EXCEPTIONS
# endif
@@ -484,56 +471,6 @@ inline void _trim_names(const char * const *raw_names,
-// General underlying types.
-
-// This template is unfortunately necessary (?) due to the lack of
-// in C++98. , this template could be replaced with a
-// combination of std::conditional and std::is_integral.
-template
-struct _representation { typedef typename T::integral_representation type; };
-
-template <> struct _representation { typedef bool type; };
-template <> struct _representation { typedef char type; };
-template <> struct _representation { typedef wchar_t type; };
-template <> struct _representation { typedef signed char type; };
-template <> struct _representation
- { typedef unsigned char type; };
-template <> struct _representation { typedef short type; };
-template <> struct _representation
- { typedef unsigned short type; };
-template <> struct _representation { typedef int type; };
-template <> struct _representation { typedef unsigned int type; };
-template <> struct _representation { typedef long type; };
-template <> struct _representation
- { typedef unsigned long type; };
-
-#ifdef BETTER_ENUMS__HAVE_LONG_LONG
-
-template <> struct _representation { typedef long long type; };
-template <> struct _representation
- { typedef unsigned long long type; };
-
-#endif
-
-#ifdef BETTER_ENUMS__HAVE_NEW_CHAR_TYPES
-
-template <> struct _representation { typedef char16_t type; };
-template <> struct _representation { typedef char32_t type; };
-
-#endif
-
-template
-struct integral_mapping {
- typedef typename _representation::type integral_representation;
-
- BETTER_ENUMS__CONSTEXPR static integral_representation
- to_integral(const T &v) { return (integral_representation)v; }
- BETTER_ENUMS__CONSTEXPR static T
- from_integral(integral_representation n) { return T(n); }
-};
-
-
-
// Eager initialization.
template
struct _initialize_at_program_start {
@@ -618,13 +555,6 @@ constexpr const char *_final_ ## index = \
// The enums proper.
-// TODO Convert integral to underlying only at the last possible moment, if the
-// integral value is valid. This should prevent unexpected behavior (conversions
-// during scans).
-
-// TODO Choose the right return type semantics once the _values array
-// representation is chosen: values if integral, const references if underlying.
-
#define BETTER_ENUMS__NS(EnumType) better_enums::_data_ ## EnumType
#ifdef BETTER_ENUMS__VC2008_WORKAROUNDS
@@ -656,45 +586,21 @@ class Enum { \
private: \
typedef ::better_enums::optional _optional; \
typedef ::better_enums::optional _optional_index; \
- typedef ::better_enums::integral_mapping _mapping; \
\
public: \
- typedef Underlying _underlying; \
- typedef _mapping::integral_representation _integral; \
+ typedef Underlying _integral; \
\
enum _enumerated SetUnderlyingType(Underlying) { __VA_ARGS__ }; \
\
- BETTER_ENUMS__CONSTEXPR Enum(_enumerated value) : \
- _value(_mapping::from_integral(value)) { } \
+ BETTER_ENUMS__CONSTEXPR Enum(_enumerated value) : _value(value) { } \
\
BETTER_ENUMS__COPY_CONSTRUCTOR(Enum) \
\
BETTER_ENUMS__CONSTEXPR operator SwitchType(Enum)() const \
{ \
- return (SwitchType(Enum))_mapping::to_integral(_value); \
+ return SwitchType(Enum)(_value); \
} \
\
- _underlying& operator *() { return _value; } \
- BETTER_ENUMS__CONSTEXPR const _underlying& operator *() const \
- { return _value; } \
- \
- _underlying* operator ->() { return &_value; } \
- BETTER_ENUMS__CONSTEXPR const _underlying* operator ->() const \
- { return &_value; } \
- \
- _underlying _to_underlying() { return _value; } \
- BETTER_ENUMS__CONSTEXPR const _underlying& _to_underlying() const \
- { return _value; } \
- \
- BETTER_ENUMS__IF_EXCEPTIONS( \
- BETTER_ENUMS__CONSTEXPR static Enum \
- _from_underlying(const _underlying &value); \
- ) \
- BETTER_ENUMS__CONSTEXPR static Enum \
- _from_underlying_unchecked(const _underlying &value); \
- BETTER_ENUMS__CONSTEXPR static _optional \
- _from_underlying_nothrow(const _underlying &value); \
- \
BETTER_ENUMS__CONSTEXPR _integral _to_integral() const; \
BETTER_ENUMS__IF_EXCEPTIONS( \
BETTER_ENUMS__CONSTEXPR static Enum _from_integral(_integral value); \
@@ -717,7 +623,7 @@ class Enum { \
BETTER_ENUMS__CONSTEXPR static _optional \
_from_string_nocase_nothrow(const char *name); \
\
- BETTER_ENUMS__CONSTEXPR static bool _is_valid(const _underlying &value); \
+ BETTER_ENUMS__CONSTEXPR static bool _is_valid(_integral value); \
BETTER_ENUMS__CONSTEXPR static bool _is_valid(const char *name); \
BETTER_ENUMS__CONSTEXPR static bool _is_valid_nocase(const char *name); \
\
@@ -736,18 +642,18 @@ class Enum { \
BETTER_ENUMS__CONSTEXPR static _value_iterable _values(); \
ToStringConstexpr static _name_iterable _names(); \
\
- _underlying _value; \
+ _integral _value; \
\
private: \
- Enum() : _value(_mapping::from_integral(0)) { } \
+ Enum() : _value(0) { } \
\
- explicit BETTER_ENUMS__CONSTEXPR Enum(const _underlying &value) : \
+ explicit BETTER_ENUMS__CONSTEXPR Enum(const _integral &value) : \
_value(value) { } \
\
DeclareInitialize \
\
BETTER_ENUMS__CONSTEXPR static _optional_index \
- _from_value_loop(const _underlying &value, std::size_t index = 0); \
+ _from_value_loop(_integral value, std::size_t index = 0); \
BETTER_ENUMS__CONSTEXPR static _optional_index \
_from_string_loop(const char *name, std::size_t index = 0); \
BETTER_ENUMS__CONSTEXPR static _optional_index \
@@ -778,34 +684,9 @@ operator +(Enum::_enumerated enumerated) \
return (Enum)enumerated; \
} \
\
-BETTER_ENUMS__IF_EXCEPTIONS( \
-BETTER_ENUMS__CONSTEXPR inline Enum \
-Enum::_from_underlying(const _underlying &value) \
-{ \
- return \
- ::better_enums::_or_throw( \
- _from_underlying_nothrow(value), \
- #Enum "::_from_underlying: invalid argument"); \
-} \
-) \
- \
-BETTER_ENUMS__CONSTEXPR inline Enum \
-Enum::_from_underlying_unchecked(const _underlying &value) \
-{ \
- return Enum(value); \
-} \
- \
-BETTER_ENUMS__CONSTEXPR inline Enum::_optional \
-Enum::_from_underlying_nothrow(const _underlying &value) \
-{ \
- return \
- ::better_enums::_map_index(BETTER_ENUMS__NS(Enum)::_value_array, \
- _from_value_loop(value)); \
-} \
- \
BETTER_ENUMS__CONSTEXPR inline Enum::_integral Enum::_to_integral() const \
{ \
- return _mapping::to_integral(_value); \
+ return _integral(_value); \
} \
\
BETTER_ENUMS__CONSTEXPR inline Enum \
@@ -826,7 +707,9 @@ 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(_mapping::from_integral(value)); \
+ return \
+ ::better_enums::_map_index(BETTER_ENUMS__NS(Enum)::_value_array, \
+ _from_value_loop(value)); \
} \
\
ToStringConstexpr inline const char* Enum::_to_string() const \
@@ -873,7 +756,7 @@ Enum::_from_string_nocase_nothrow(const char *name) \
_from_string_nocase_loop(name)); \
} \
\
-BETTER_ENUMS__CONSTEXPR inline bool Enum::_is_valid(const _underlying &value) \
+BETTER_ENUMS__CONSTEXPR inline bool Enum::_is_valid(_integral value) \
{ \
return _from_value_loop(value); \
} \
@@ -908,14 +791,14 @@ ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
DefineInitialize(Enum) \
\
BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
-Enum::_from_value_loop(const Enum::_underlying &value, std::size_t index) \
+Enum::_from_value_loop(Enum::_integral value, std::size_t index) \
{ \
return \
- 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); \
+ index == _size() ? \
+ _optional_index() : \
+ BETTER_ENUMS__NS(Enum)::_value_array[index]._value == value ? \
+ _optional_index(index) : \
+ _from_value_loop(value, index + 1); \
} \
\
BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
@@ -962,7 +845,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
// C++11
#define BETTER_ENUMS__CXX11_UNDERLYING_TYPE(Underlying) \
- : ::better_enums::integral_mapping::integral_representation
+ : Underlying
// C++98, C++11
#define BETTER_ENUMS__REGULAR_ENUM_SWITCH_TYPE(Type) \
@@ -977,9 +860,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::integral_mapping::integral_representation \
- { __VA_ARGS__ };
+ enum class _EnumClassForSwitchStatements : Underlying { __VA_ARGS__ };
// C++98
#define BETTER_ENUMS__CXX98_TRIM_STRINGS_ARRAYS(Enum, ...) \
diff --git a/example/102-any-underlying.cc b/example/102-any-underlying.cc
deleted file mode 100644
index ffe4d5c..0000000
--- a/example/102-any-underlying.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// This file was generated automatically.
-
-// Non-integral underlying types
-//
-// The underlying type of a Better Enum doesn't have to be an integral type. It
-// can be any literal type T, as long as you provide a constexpr two-way mapping
-// between T and an integral type of your choosing. This also works in C++98 -
-// though then, of course, T doesn't have to be literal and the mapping doesn't
-// have to be constexpr. In C++98, everything involving T will simply be done by
-// Better Enums at run time.
-//
-// This feature is semi-experimental. I am considering relaxing the requirements
-// on T so that it doesn't have to be literal. I can use a reinterpret_cast to
-// make a mapping automatically. This will make non-integral underlying types
-// easier to use, but will also prevent usage at compile time, which
-// unfortunately has structural consequences for the implementation of Better
-// Enums, and additional semantic consequences for usage, even at run time.
-//
-// In the meantime, here's how to have a non-integral underlying type in the
-// current version.
-
-#include
-#include
-typedef unsigned char uint8_t; // not in C++98.
-
-
-
-// The underlying type. A color triplet.
-struct html_color {
- uint8_t r, g, b;
-
- constexpr html_color(uint8_t _r, uint8_t _g, uint8_t _b) :
- r(_r), g(_g), b(_b) { }
-};
-
-// The mapping. It just stuffs bits to get the same effect as
-// reinterpret_cast, except reinterpret_cast is not available in constexpr
-// functions, so we have to write the bit manipulations out. On modern
-// C++11 compilers, you don't have to enter the better_enums namespace like
-// this - you can just do
-// struct ::better_enums::integral_mapping { ...
-namespace better_enums {
-
-template <>
-struct integral_mapping {
- using integral_representation = unsigned int;
-
- constexpr static html_color from_integral(unsigned int i)
- { return html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
-
- constexpr static unsigned int to_integral(html_color c)
- { return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
-};
-
-}
-
-
-
-// The enum itself.
-BETTER_ENUM(Color, html_color,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954)
-
-// Now, we can do:
-
-int main()
-{
- Color color = Color::darksalmon;
-
- std::cout << std::hex;
- std::cout << "Red component: " << (int)color->r << std::endl;
- std::cout << "Green component: " << (int)color->g << std::endl;
- std::cout << "Blue component: " << (int)color->b << std::endl;
-
- std::cout << color._to_string() << std::endl;
-
- switch (color) {
- case Color::darksalmon: return 0;
- case Color::purplemimosa: return 1;
- case Color::slimegreen: return 2;
- }
-
- return 0;
-}
-
-// This prints each component, the name of the color ("darksalmon"), and then
-// exits from the switch with status 0.
-//
-// Constructors in initializers
-//
-// The above declaration used only numbers in initializers, but it is actually
-// possible to use constructors of html_color. We have to add a constexpr
-// converting operator directly to html_color, however:
-//
-// struct better_html_color {
-// uint8_t r, g, b;
-//
-// constexpr better_html_color(uint8_t _r, uint8_t _g, uint8_t _b) :
-// r(_r), g(_g), b(_b) { }
-//
-// // This is new:
-// constexpr operator unsigned int() const
-// { return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }
-// };
-//
-// namespace better_enums {
-//
-// template <>
-// struct integral_mapping {
-// using integral_representation = unsigned int;
-//
-// constexpr static better_html_color from_integral(unsigned int i)
-// {
-// return better_html_color(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff);
-// }
-//
-// constexpr static unsigned int to_integral(better_html_color c)
-// { return (unsigned int)c.r << 16 | (unsigned int)c.g << 8 | c.b; }
-// };
-//
-// }
-//
-// This allows:
-//
-// BETTER_ENUM(BetterColor, better_html_color,
-// darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
-// slimegreen = 0xbce954,
-// celeste = better_html_color(0x50, 0xeb, 0xec))
-//
-// If you can't edit your literal type to add this converting operator, or don't
-// want to for type safety reasons, you can achieve a similar effect by
-// declaring an intermediate type U that html_color can convert to, that can
-// convert to the integral type. Then, cast your constructor call to U. The type
-// U is for declarations only.
-//
-// Constructors in initializers require C++11. Also, g++ doesn't support this
-// before 5.1.
-//
-// Letting the compiler enumerate your type
-//
-// Of course, as long as the values are valid, you can let the compiler
-// enumerate your type as in a regular enum, by omitting initializers:
-//
-// BETTER_ENUM(FD, file_descriptor,
-// STDIN, STDOUT, STDERR, SomePipeYourDaemonHas, ...)
-//
-// Here, FD::STDIN maps to the integral representation 0, STDOUT to 1, and so
-// on.
-//
-// Discussion
-//
-// This feature is still semi-experimental, though I expect it to remain stable,
-// except perhaps that I will make it possible to infer the type
-// integral_representation.
-//
-// Any opinions are welcome.
-//
-// 1. The main reason Better Enums needs you to supply and explicit mapping is
-// because it can't just get the "bits" of objects of underlying type in
-// constexpr code. Both reinterpret_cast and union abuse seem to be
-// forbidden in constexpr functions.
-// 2. There is currently no way to have two different integral representaitons
-// for the same underlying type in different enums. I don't think that's a
-// major use case at this point, however.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 2565222..74b6350 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -112,14 +112,14 @@ endforeach(TEST)
set(EXAMPLES
1-hello-world 2-conversions 3-iterate 4-switch 6-iostreams 7-safety
- 8-representation 9-constexpr 101-special-values 102-any-underlying
- 103-bitset 104-quine 105-c++17-reflection)
-
-set(SKIPPED_FOR_CXX98
- 5-map 9-constexpr 101-special-values 102-any-underlying 103-bitset 104-quine
+ 8-representation 9-constexpr 101-special-values 103-bitset 104-quine
105-c++17-reflection)
-set(SKIPPED_FOR_STRICT_CONVERSION 4-switch 102-any-underlying)
+set(SKIPPED_FOR_CXX98
+ 5-map 9-constexpr 101-special-values 103-bitset 104-quine
+ 105-c++17-reflection)
+
+set(SKIPPED_FOR_STRICT_CONVERSION 4-switch)
if(CONFIGURATION STREQUAL CXX98 OR NOT SUPPORTS_CONSTEXPR)
list(REMOVE_ITEM EXAMPLES ${SKIPPED_FOR_CXX98})
diff --git a/test/cxxtest/underlying.h b/test/cxxtest/underlying.h
deleted file mode 100644
index 900d4a6..0000000
--- a/test/cxxtest/underlying.h
+++ /dev/null
@@ -1,180 +0,0 @@
-#include
-#include
-
-// This test uses internal constants declared by feature testing macros in
-// enum.h. They are not part of the public interface, but are used here to avoid
-// duplication of definitions for C++11 and C++98.
-//
-// BETTER_ENUMS__CONSTEXPR is a synonym for constexpr when available, and
-// othewise expands to nothing.
-
-
-
-// Using a type trait.
-struct html_color_1 {
- unsigned char r, g, b;
-
- BETTER_ENUMS__CONSTEXPR
- html_color_1(unsigned char _r, unsigned char _g, unsigned char _b) :
- r(_r), g(_g), b(_b) { }
-};
-
-// 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 integral_mapping {
- typedef unsigned int integral_representation;
-
- BETTER_ENUMS__CONSTEXPR static html_color_1 from_integral(unsigned int i)
- { return html_color_1(i >> 16 & 0xff, i >> 8 & 0xff, i & 0xff); }
-
- BETTER_ENUMS__CONSTEXPR static unsigned int to_integral(html_color_1 v)
- { return (unsigned int)v.r << 16 | (unsigned int)v.g << 8 | v.b; }
-};
-
-}
-
-BETTER_ENUM(HtmlColor1, html_color_1,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954)
-
-
-
-// Using member definitions.
-struct html_color_2 {
- unsigned char r, g, b;
-
- BETTER_ENUMS__CONSTEXPR
- html_color_2(unsigned char _r, unsigned char _g, unsigned char _b) :
- r(_r), g(_g), b(_b) { }
-
-
-
- typedef unsigned int integral_representation;
-
- explicit BETTER_ENUMS__CONSTEXPR html_color_2(unsigned int i) :
- r(i >> 16 & 0xff), g(i >> 8 & 0xff), b(i & 0xff) { }
-
- BETTER_ENUMS__CONSTEXPR operator unsigned int() const
- { return (unsigned int)r << 16 | (unsigned int)g << 8 | b; }
-};
-
-// Initializers are not supported before GCC 5.1, even with a literal type and
-// constexpr conversion to integer.
-#ifdef BETTER_ENUMS__HAVE_CONSTEXPR
-# ifdef __GNUC__
-# ifdef __clang__
-# define SUPPORT_INITIALIZER
-# else
-# if __GNUC__ >= 5
-# define SUPPORT_INITIALIZER
-# endif
-# endif
-# endif
-#endif
-
-#ifdef SUPPORT_INITIALIZER
-BETTER_ENUM(HtmlColor2, html_color_2,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954, celeste = html_color_2(0x50, 0xeb, 0xec))
-#else
-BETTER_ENUM(HtmlColor2, html_color_2,
- darksalmon = 0xc47451, purplemimosa = 0x9e7bff,
- slimegreen = 0xbce954)
-#endif
-
-
-
-class UnderlyingTypeTests : public CxxTest::TestSuite {
- public:
- void test_basics_and_operators()
- {
- HtmlColor1 color_1 = HtmlColor1::darksalmon;
-
- TS_ASSERT_EQUALS(color_1->r, 0xc4);
- TS_ASSERT_EQUALS(color_1->g, 0x74);
- TS_ASSERT_EQUALS(color_1->b, 0x51);
-
- TS_ASSERT_EQUALS(sizeof(HtmlColor1), sizeof(html_color_1));
-
- HtmlColor2 color_2 = HtmlColor2::purplemimosa;
-
- TS_ASSERT_EQUALS(color_2->r, 0x9e);
- TS_ASSERT_EQUALS(color_2->g, 0x7b);
- TS_ASSERT_EQUALS(color_2->b, 0xff);
-
- TS_ASSERT_EQUALS(sizeof(HtmlColor2), sizeof(html_color_2));
-
-#ifdef SUPPORT_INITIALIZER
- HtmlColor2 color_3 = HtmlColor2::celeste;
-
- TS_ASSERT_EQUALS(color_3->r, 0x50);
- TS_ASSERT_EQUALS(color_3->g, 0xeb);
- TS_ASSERT_EQUALS(color_3->b, 0xec);
-#endif
-
- color_1->r = 0;
-
- const HtmlColor1 const_color = HtmlColor1::slimegreen;
- TS_ASSERT_EQUALS(const_color->r, 0xbc);
-
- html_color_1 &color_1_reference = *color_1;
- const html_color_1 &const_color_reference = *const_color;
-
- TS_ASSERT_EQUALS(color_1_reference.r, 0);
- TS_ASSERT_EQUALS(const_color_reference.r, 0xbc);
- }
-
- void test_conversion_functions()
- {
- HtmlColor2 color_1 = HtmlColor2::darksalmon;
- html_color_2 color_1_underlying = color_1._to_underlying();
-
- TS_ASSERT_EQUALS(color_1_underlying.r, color_1->r);
- TS_ASSERT_EQUALS(color_1_underlying.g, color_1->g);
- TS_ASSERT_EQUALS(color_1_underlying.b, color_1->b);
-
- color_1_underlying = html_color_2(HtmlColor2::slimegreen);
- color_1 = HtmlColor2::_from_underlying(color_1_underlying);
-
- TS_ASSERT_EQUALS(color_1->r, color_1_underlying.r);
- TS_ASSERT_EQUALS(color_1->g, color_1_underlying.g);
- TS_ASSERT_EQUALS(color_1->b, color_1_underlying.b);
-
- color_1_underlying = html_color_2(1, 2, 3);
- color_1 = HtmlColor2::_from_underlying_unchecked(color_1_underlying);
-
- TS_ASSERT_EQUALS(color_1->r, color_1_underlying.r);
- TS_ASSERT_EQUALS(color_1->g, color_1_underlying.g);
- TS_ASSERT_EQUALS(color_1->b, color_1_underlying.b);
- }
-
- void test_switch()
- {
-#ifndef BETTER_ENUMS_STRICT_CONVERSION
-
- HtmlColor1 html_color_1 = HtmlColor1::purplemimosa;
-
- switch (html_color_1) {
- case HtmlColor1::darksalmon: TS_ASSERT(false); break;
- case HtmlColor1::purplemimosa: TS_ASSERT(true); break;
- case HtmlColor1::slimegreen: TS_ASSERT(false); break;
- }
-
-#else
-# ifdef BETTER_ENUMS__HAVE_CONSTEXPR
-
- HtmlColor1 html_color_1 = HtmlColor1::purplemimosa;
-
- switch (html_color_1) {
- case +HtmlColor1::darksalmon: TS_ASSERT(false); break;
- case +HtmlColor1::purplemimosa: TS_ASSERT(true); break;
- case +HtmlColor1::slimegreen: TS_ASSERT(false); break;
- }
-
-# endif
-#endif
- }
-};