Статически различать перечисление и класс перечисления в С++?

У меня есть класс обработчика событий, который использует аргумент шаблона для установки типа события. Я хочу, чтобы эти типы событий были перечисленными классами размером в один байт. Статическое утверждение относительно размера не является проблемой, но я не могу найти в Интернете информацию о том, как статически различать enum и enum class.

Решение, которое у меня есть сейчас, состоит в том, чтобы утверждать для перечислений, используя C++ внешний интерфейс реализует синтаксические расширения, а затем утверждает правильный размер. На большинстве платформ это работает, так как перечисление использует тип int (который чаще всего больше одного байта).

Но это привело бы к слегка вводящим в заблуждение сообщениям об ошибках. Я люблю быть тщательным.

Какие проверки я мог бы выполнить, чтобы передать перечисление класса, но не пройти с обычным старым перечислением?


Я не могу использовать type_traits, так как используемый мной компилятор (avr-gcc) его не поддерживает. Однако я постоянно внедряю свои собственные type_traits, когда возникает необходимость. Так что любые советы по решениям в type_traits все еще могут быть полезны!


Минимальный пример:

// 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!");
};

Использование:

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

Цель:

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

person Smartskaft2    schedule 15.06.2020    source источник


Ответы (1)


Ключевое различие между перечислениями без области действия и видом с областью действия (enum class) заключается в том, что первые неявно преобразуются в свой базовый тип, а вторые — нет. Поскольку вам интересно, как будет выглядеть решение type_traits, вы можете проверить (не полностью протестировано, возможно, не подходит для SFINAE):

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!");

Если AVR-GCC имеет встроенный underlying_type, вам нужно только дополнить признак is_convertible (который можно реализовать даже в C++03).

person StoryTeller - Unslander Monica    schedule 15.06.2020