Можно ли преобразовать класс перечисления в базовый тип?

Есть ли способ конвертировать поле enum class в базовый тип? Я думал, что это будет автоматически, но, видимо, нет.

enum class my_fields : unsigned { field = 1 };

unsigned a = my_fields::field;

Это назначение отклоняется GCC. error: cannot convert 'my_fields' to 'unsigned int' in assignment.

Ответ 1

Я думаю, вы можете использовать std:: basic_type, чтобы узнать базовый тип, а затем использовать cast:

#include <type_traits> //for std::underlying_type

typedef std::underlying_type<my_fields>::type utype;

utype a = static_cast<utype>(my_fields::field);

При этом вам не нужно предполагать базовый тип, или вам не нужно упоминать его в определении enum class как enum class my_fields : int { .... } или так.

Вы даже можете написать генераторную функцию преобразования, которая должна иметь возможность преобразовать любой enum class в его основной тип интеграла:

template<typename E>
constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type 
{
   return static_cast<typename std::underlying_type<E>::type>(e);
}

затем используйте его:

auto value = to_integral(my_fields::field);

auto redValue = to_integral(Color::Red);//where Color is an enum class!

И поскольку функция объявлена ​​как constexpr, вы можете использовать ее там, где требуется постоянное выражение:

int a[to_integral(my_fields::field)]; //declaring an array

std::array<int, to_integral(my_fields::field)> b; //better!

Надеюсь, что это поможет.

Ответ 2

Вы не можете преобразовать его неявно, но явное приведение возможно:

enum class my_fields : unsigned { field = 1 };

// ...

unsigned x = my_fields::field; // ERROR!
unsigned x = static_cast<unsigned>(my_fields::field); // OK

Также обратите внимание на то, что точка с запятой должна быть после закрытой фигурной скобки в определении перечисления, а не раньше.

Ответ 3

Я нахожу следующую функцию underlying_cast полезной при правильной сериализации значений перечисления.

namespace util
{

namespace detail
{
    template <typename E>
    using UnderlyingType = typename std::underlying_type<E>::type;

    template <typename E>
    using EnumTypesOnly = typename std::enable_if<std::is_enum<E>::value, E>::type;

}   // namespace util.detail


template <typename E, typename = detail::EnumTypesOnly<E>>
constexpr detail::UnderlyingType<E> underlying_cast(E e) {
    return static_cast<detail::UnderlyingType<E>>(e);
}

}   // namespace util

enum SomeEnum : uint16_t { A, B };

void write(SomeEnum /*e*/) {
    std::cout << "SomeEnum!\n";
}

void write(uint16_t /*v*/) {
    std::cout << "uint16_t!\n";
}

int main(int argc, char* argv[]) {
    SomeEnum e = B;
    write(util::underlying_cast(e));
    return 0;
}