열거 형 클래스를 기본 형식으로 변환 할 수 있습니까?


112

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.


4
기본 유형으로 변환하려면 enum.
Pubby 2013-01-29

1
참고로이 규칙은 [C++11: 7.2/9].
궤도의 경쾌함 레이스

5
@Pubby 슬프게도 범위가 지정되지 않은 'enum'은 모든 열거 자로 외부 범위를 오염시킵니다. 안타깝게도 기본 유형으로 암시 적으로 변환하는 동시에 범위를 깔끔하게 중첩하는 두 세계 (어쨌든 C ++ 14 기준)의 장점은 없습니다 (더 많이 파생 된 유형을 기본 유형을 취하는 함수에 대한 값 또는 참조).
Dwayne Robinson

2
@DwayneRobinson 네 그렇습니다. 범위가 지정되지 않은 열거 형을 구조체 또는 (더 바람직하게는) 네임 스페이스 안에 붙입니다. 따라서 범위가 지정되고 여전히 암시 적 int 변환이 있습니다. (하지만 int로 변환해야하는 이유에 대해 두 번 생각하고 아마도 더 나은 접근 방식이 있는지 고려할 것입니다.)
Pharap

답변:


178

std :: underlying_type 을 사용 하여 기본 유형을 알고 캐스트를 사용할 수 있다고 생각합니다 .

#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!

이제 우리는 미래에 있습니다 :template <typename T> auto to_integral(T e) { return static_cast<std::underlying_type_t<T>>(e); }
Ryan Haining

1
@RyanHaining : 감사합니다. (BTW, 당신은 constexpr미래에도 마찬가지입니다. 사실 제가 2013 년에 가졌던 것보다 훨씬 더 강력한 것입니다. : P)
Nawaz

41

암시 적으로 변환 할 수는 없지만 명시 적 캐스트는 가능합니다.

enum class my_fields : unsigned { field = 1 };

// ...

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

또한 세미콜론은 열거 형 정의에서 닫혀진 중괄호 뒤에 있어야하며 이전이 아니 어야합니다 .


0

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;
}

0

다른 사람들이 지적했듯이 암시 적 캐스트는 없지만 명시 적 static_cast. 내 코드에서 다음 도우미 함수를 사용하여 열거 형 및 기본 클래스간에 변환합니다.

    template<typename EnumType>
    constexpr inline decltype(auto) getIntegralEnumValue(EnumType enumValue)
    {
        static_assert(std::is_enum<EnumType>::value,"Enum type required");
        using EnumValueType = std::underlying_type_t<EnumType>;
        return static_cast<EnumValueType>(enumValue);
    }

    template<typename EnumType,typename IntegralType>
    constexpr inline EnumType toEnum(IntegralType value)
    {
        static_assert(std::is_enum<EnumType>::value,"Enum type required");
        static_assert(std::is_integral<IntegralType>::value, "Integer required");
        return static_cast<EnumType>(value);
    }

    template<typename EnumType,typename UnaryFunction>
    constexpr inline void setIntegralEnumValue(EnumType& enumValue, UnaryFunction integralWritingFunction)
    {
        // Since using reinterpret_cast on reference to underlying enum type is UB must declare underlying type value and write to it and then cast it to enum type
        // See discussion on /programming/19476818/is-it-safe-to-reinterpret-cast-an-enum-class-variable-to-a-reference-of-the-unde

        static_assert(std::is_enum<EnumType>::value,"Enum type required");

        auto enumIntegralValue = getIntegralEnumValue(enumValue);
        integralWritingFunction(enumIntegralValue);
        enumValue = toEnum<EnumType>(enumIntegralValue);
    }

사용 코드

enum class MyEnum {
   first = 1,
   second
};

MyEnum myEnum = MyEnum::first;
std::cout << getIntegralEnumValue(myEnum); // prints 1

MyEnum convertedEnum = toEnum(1);

setIntegralEnumValue(convertedEnum,[](auto& integralValue) { ++integralValue; });
std::cout << getIntegralEnumValue(convertedEnum); // prints 2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.