mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-07 01:06:42 +08:00
Forbade nearly all implicit conversions to integral types.
Each Better Enum now has an internal enum class type to which it is convertible, instead of being convertible to the regular enum that defines its constants. switch statements are compiled at the enum class type. This comes at the price of the user having to type +Enum::Constant instead of Enum::Constant in cases, in order to trigger an explicit promotion of the pre-C++11 enum to Better Enum, so it can then be implicitly converted to the enum class. The remaining "hole" is that direct references to constants (Enum::Constant) are still implicitly convertible to integral types, because they have naked pre-C++11 enum type.
This commit is contained in:
parent
08dbe47edd
commit
1b3d1cc784
20
enum.h
20
enum.h
@ -597,6 +597,8 @@ struct _Base { \
|
|||||||
\
|
\
|
||||||
enum { __VA_ARGS__ }; \
|
enum { __VA_ARGS__ }; \
|
||||||
\
|
\
|
||||||
|
enum class _Case : Integral { __VA_ARGS__ }; \
|
||||||
|
\
|
||||||
constexpr const _Base _value_array[] = \
|
constexpr const _Base _value_array[] = \
|
||||||
{ _ENUM_EAT_ASSIGN(_Base, __VA_ARGS__) }; \
|
{ _ENUM_EAT_ASSIGN(_Base, __VA_ARGS__) }; \
|
||||||
\
|
\
|
||||||
@ -618,19 +620,6 @@ constexpr const _Iterable<const char*> _names{_name_array, _size}; \
|
|||||||
|
|
||||||
#define _ENUM_NS(EnumType) _enum::_data_ ## EnumType
|
#define _ENUM_NS(EnumType) _enum::_data_ ## EnumType
|
||||||
|
|
||||||
#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: \
|
||||||
@ -727,7 +716,10 @@ class EnumType : public _ENUM_NS(EnumType)::_Base { \
|
|||||||
return _from_string_nocase_loop(name); \
|
return _from_string_nocase_loop(name); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
_ENUM_CONVERSION_FOR_SWITCH(Integral, __VA_ARGS__); \
|
constexpr operator _ENUM_NS(EnumType)::_Case() const \
|
||||||
|
{ \
|
||||||
|
return (_ENUM_NS(EnumType)::_Case)_value; \
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
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; \
|
||||||
|
|||||||
@ -10,15 +10,15 @@ void respond_to_channel(Channel channel)
|
|||||||
// Try adding an extra case or removing one. Your compiler should issue a
|
// Try adding an extra case or removing one. Your compiler should issue a
|
||||||
// warning.
|
// warning.
|
||||||
switch (channel) {
|
switch (channel) {
|
||||||
case Channel::Red:
|
case +Channel::Red:
|
||||||
std::cout << "red channel" << std::endl;
|
std::cout << "red channel" << std::endl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel::Green:
|
case +Channel::Green:
|
||||||
std::cout << "green channel" << std::endl;
|
std::cout << "green channel" << std::endl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Channel::Blue:
|
case +Channel::Blue:
|
||||||
std::cout << "blue channel" << std::endl;
|
std::cout << "blue channel" << std::endl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ constexpr Enum maximum(Enum accumulator = Enum::_values[0], size_t index = 1)
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
index >= Enum::_size ? accumulator :
|
index >= Enum::_size ? accumulator :
|
||||||
Enum::_values[index] > accumulator ?
|
+Enum::_values[index] > accumulator ?
|
||||||
maximum(+Enum::_values[index], index + 1) :
|
maximum(+Enum::_values[index], index + 1) :
|
||||||
maximum(accumulator, index + 1);
|
maximum(accumulator, index + 1);
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ ENUM(Channel, int, Red, Green, Blue);
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
using ChannelSet = std::bitset<maximum<Channel>() + 1>;
|
using ChannelSet = std::bitset<maximum<Channel>().to_integral() + 1>;
|
||||||
|
|
||||||
ChannelSet red_only;
|
ChannelSet red_only;
|
||||||
red_only.set(Channel::Red);
|
red_only.set(Channel::Red);
|
||||||
@ -33,7 +33,7 @@ int main()
|
|||||||
std::cout
|
std::cout
|
||||||
<< channel.to_string()
|
<< channel.to_string()
|
||||||
<< " bit is set to "
|
<< " bit is set to "
|
||||||
<< red_and_blue[channel]
|
<< red_and_blue[channel.to_integral()]
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,13 +56,21 @@ static_assert_1(!(std::is_constructible<Channel, Depth>()));
|
|||||||
|
|
||||||
// Intended implicit conversions.
|
// Intended implicit conversions.
|
||||||
static_assert_1((std::is_convertible<Channel::_Enumerated, Channel>()));
|
static_assert_1((std::is_convertible<Channel::_Enumerated, Channel>()));
|
||||||
static_assert_1(!(std::is_convertible<Channel::_Integral, Channel>()));
|
|
||||||
static_assert_1(!(std::is_convertible<Depth, Channel>()));
|
|
||||||
static_assert_1(!(std::is_convertible<Channel, Depth>()));
|
|
||||||
|
|
||||||
// Regrettable implicit conversions.
|
// Regrettable implicit conversions.
|
||||||
static_assert_1((std::is_convertible<Channel, Channel::_Enumerated>()));
|
static_assert_1((std::is_convertible<decltype(Channel::Red),
|
||||||
static_assert_1((std::is_convertible<Channel, Channel::_Integral>()));
|
Channel::_Integral>()));
|
||||||
|
|
||||||
|
// Disallowed implicit conversions.
|
||||||
|
static_assert_1(!(std::is_convertible<Channel::_Integral, Channel>()));
|
||||||
|
static_assert_1(!(std::is_convertible<Channel, Channel::_Integral>()));
|
||||||
|
static_assert_1(!(std::is_convertible<Depth, Channel>()));
|
||||||
|
static_assert_1(!(std::is_convertible<Channel, Depth>()));
|
||||||
|
static_assert_1(!(std::is_convertible<Channel, Channel::_Enumerated>()));
|
||||||
|
static_assert_1(!(std::is_convertible<decltype(+Channel::Red),
|
||||||
|
Channel::_Integral>()));
|
||||||
|
static_assert_1(!(std::is_convertible<decltype(Channel::_values[0]),
|
||||||
|
Channel::_Integral>()));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user