Reputation: 510
I have an event handler class that uses a template argument to set the event type. I want to enforce these event types to be enum classes of one byte size. Static assertion against the size is not an issue, but I cannot find information online on how to statically distinguish between an enum and enum class.
The solution I have now is to assert for enums using the C++ front-end implements syntactic extensions and then assert the correct size. On most platforms this works, since an enum uses the int
type (which most often is larger than one byte).
But this would lead to slightly misleading error messages. I like to be thorough.
What checks could I do that would pass on a class enum, but fail with a regular old enum?
I cannot use type_traits
, since the compiler I use (avr-gcc) does not support it. I am however continuously implementing my own type_traits
, when a need rises. So any tips on solutions in type_traits
could still be useful!
Minimal example:
// Event types
enum class tPass : uint8_t {};
enum class tFailSize : uint16_t {}; // Fail on size!
enum tFailType {}; // Currently fails on size, would like to fail on type!
// Event handler
template <typename TEvent>
class tEventHandler
{
static_assert(__is_enum(TEvent), "Must be class enum!"); // Doesn't really check for CLASS enums
static_assert(1 == sizeof(TEvent), "Must be one byte!");
};
Usage:
auto handler = tEventHandler<tPass>(); // Ok!
// auto handler2 = tEventHandler<tFailSize>(); // error: static assertion failed: Must be one byte!
// auto handler3 = tEventHandler<tFailType>(); // error: static assertion failed: Must be one byte! <----- THIS
Goal:
auto handler = tEventHandler<tPass>(); // Ok!
// auto handler2 = tEventHandler<tFailSize>(); // error: static assertion failed: Must be one byte!
// auto handler3 = tEventHandler<tFailType>(); // error: static assertion failed: Must be class enum! <--- THIS
Upvotes: 8
Views: 765
Reputation: 170064
A key distinction between unscoped enumerations and the scoped kind (enum class
), is that the former implicitly convert to their underlying type, whereas the latter do not. Since you are interested in how the type_traits
solution would look, you can check (not entirely tested, may not be SFINAE friendly):
static_assert(std::is_enum<TEvent>::value, "Must be a scoped enum!");
static_assert(!std::is_convertible<TEvent, typename std::underlying_type<TEvent>::type>::value,
"Must be a scoped enum!");
If AVR-GCC has an underlying_type
intrinsic, then you need only supplement the is_convertible
trait (which is even implementable in C++03).
Upvotes: 6