연속 열거 형 C ++ 11


17

열거 형이 연속적 인 경우 C ++ 11을 확인하는 방법이 있습니까?

열거 형 값을 제공하지 않는 것이 유효합니다. C ++ 14, C ++ 17 또는 C ++ 20에 유형 특성과 같은 기능이 열거 형이 연속적인지 확인할 수 있습니까? 이것은 static_assert에서 사용됩니다.

작은 예는 다음과 같습니다.

enum class Types_Discontinuous {
  A = 10,
  B = 1,
  C = 100
};

enum class Types_Continuous {
  A = 0,
  B = 1,
  C = 2
};

static_assert(SOME_TEST<Types_Discontinuous>::value, "Enum should be continuous"); // Fails
static_assert(SOME_TEST<Types_Continuous>::value, "Enum should be continuous");    // Passes

1
평균 오름차순을 의미하거나 모든 값에 대해 0으로 시작한 다음 +1을 의미합니까?
RoQuOTriX

5
열거 레이블을 열거 할 방법이 없으므로 프로그램 자체에서 열거 레이블을 수행 할 수 없습니다.
일부 프로그래머 친구

1
흥미 롭군 컴파일러가 계승을 계산할 수있는 방법에 대한 템플릿 프로그래밍 라인을 생각하고 있습니다. 두 개의 경계 A와 C를 사용하여 일을 시작하고 템플릿 함수는 SFINAE를 통해에서 또는 그 사이의 모든 값의 존재 여부를 확인합니다 enum. 슬프게도 나는 하루의 직업을 가지고 있으므로이 접근법을 기반으로 답변을 공언하지만 이것을 쓸 수는 없습니다. @barry 또는 @sehe와 같은 누군가가 할 수 있다고 확신합니다.
Bathsheba

1
@RoQuOTriX 라벨에 값을 어떻게 맞추시겠습니까? 라벨 순서를 어떻게 확인 하시겠습니까? 그리고 컴파일 타임에 (필요한 static_assert) 어떻게 할 수 있습니까? "아름다운 해결책"을 만들 수없는 경우에도 일반적인 방법으로 어떻게 할 수 있는지 궁금해서 답변을 작성하십시오.
일부 프로그래머 친구

1
@Someprogrammerdude 당신이 묘사 한 것은 "아름다운"또는 좋은 해결책입니다. 내가 의미하는 바는 "쉬운"체크 솔루션으로, 모든 열거 형과 신의 축복을 위해 다시 작성해야합니다. 아무도 그렇게하지 않기를 바랍니다
RoQuOTriX

답변:


7

많은 수의 enum경우 Magic Enum 라이브러리를 사용 하여이 작업을 해킹 할 수 있습니다 . 예를 들면 다음과 같습니다.

#include "magic_enum.hpp"

template <typename Enum>
constexpr bool is_continuous(Enum = Enum{}) {
    // make sure we're actually testing an enum
    if constexpr (!std::is_enum_v<Enum>)
        return false;
    else {
        // get a sorted list of values in the enum
        const auto values = magic_enum::enum_values<Enum>();
        if (std::size(values) == 0)
            return true;

        // for every value, either it's the same as the last one or it's one larger
        auto prev = values[0];
        for (auto x : values) {
            auto next = static_cast<Enum>(magic_enum::enum_integer(prev) + 1);
            if (x != prev && x != next)
                return false;
            else
                prev = x;
        }
        return true;
    }
}

라이브러리 이름에서 알 수 있듯이 이것은 "매직"– 라이브러리는 수많은 컴파일러 관련 해킹에서 작동합니다. 따라서 "순수한 C ++"에 대한 요구 사항을 실제로 충족 시키지는 못하지만 언어에 반영 기능이있을 때까지 얻을 수있는 것만 큼 좋습니다.


그것은 실제로 마술이지만 이것은 내 상황에 가장 적합합니다.
바트

7

열거 형 값을 열거하거나 값 수와 최소값 및 최대 값을 검색 할 수있는 방법이 없기 때문에 순수 C ++에서는 불가능합니다. 그러나 컴파일러의 도움으로 원하는 것에 가까운 것을 구현할 수 있습니다. 예를 들어 gcc에서 switch명령문이 열거 형의 모든 값을 처리하지 않으면 컴파일 오류를 강제 할 수 있습니다 .

enum class my_enum {
    A = 0,
    B = 1,
    C = 2
};

#pragma GCC diagnostic push
#if __GNUC__ < 5
#pragma GCC diagnostic error "-Wswitch"
#else
#pragma GCC diagnostic error "-Wswitch-enum"
#endif

constexpr bool is_my_enum_continuous(my_enum t = my_enum())
{
    // Check that we know all enum values. Effectively works as a static assert.
    switch (t)
    {
    // Intentionally no default case.
    // The compiler will give an error if not all enum values are listed below.
    case my_enum::A:
    case my_enum::B:
    case my_enum::C:
        break;
    }

    // Check that the enum is continuous
    auto [min, max] = std::minmax({my_enum::A, my_enum::B, my_enum::C});
    return static_cast< int >(min) == 0 && static_cast< int >(max) == 2;
}

#pragma GCC diagnostic pop

분명히 이것은 주어진 열거 형에 특화되어 있지만 그러한 기능의 정의는 전처리기로 자동화 될 수 있습니다.


올바르게 이해하면 여전히 스위치 및 minmax에 대한 목록에 모든 열거 값을 작성해야합니다. 현재 여러 열거 형이 있으므로 실제로 가능하지만 내 상황에 바람직하지 않습니다.
바트

1

나는 이것에 대한 답변을보고 싶습니다. 나는 그것을 필요로했다.

불행히도 기존 유틸리티를 사용하여 이것이 가능하지 않다고 생각합니다. 이것에 대한 유형 특성을 구현하려면 컴파일러의 지원이 필요하므로 템플릿을 작성하는 것이 실현 가능하지 않습니다.

이미 특정 태그를 사용하여 열거를 확장하여 인접하고 즉시 크기를 제공합니다. enum class constructor c ++, 특정 값을 전달하는 방법은 무엇입니까?

또는 자신의 특성을 작성할 수 있습니다.

 template<T> struct IsContiguous : std::false_type {};

이것을 사용하려는 연속 열거 형을 정의 할 때마다 전문화해야합니다. 불행하게도 열거 형이 변경되면 약간의 유지 관리와주의가 필요합니다.


1
형식이 올바르게 설정되어 있으면 컴파일하는 동안 검사하는 코드 검사기를 작성할 수 있습니다.
RoQuOTriX

네 확실합니다. 당신이 그것을 쓸 수있는 능력이 있다면.
JVApen

1

모든 열거 형은 연속적입니다. 0은 항상 허용됩니다. 허용되는 가장 높은 값은 다음으로 올림 된 가장 높은 열거 자 1<<N -1(모든 비트 1)이며 그 사이의 모든 값도 허용됩니다. ([dcl.enum] 9.7.1 / 5). 음수 열거자가 정의되어 있으면 가장 낮은 열거자를 반올림하여 허용되는 가장 낮은 값을 유사하게 정의합니다.

에 정의 된 열거 enum자는 범위에 값이 있고 유형이 올바른 상수 표현식이지만 enum속성이 동일한 추가 상수를 정의 할 수 있습니다.

constexpr enum class Types_Discontinuous = static_cast<Types_Discontinuous>(2)


2
정확하지만 OP에서 정의 된 값에 대해 알고 자합니다. (PS : 다운 투표는 내 것이 아니다)
JVApen

1
@ JVApen : 그것은 정확한 문제입니다. "정의 된 값"은 열거 형 자체의 속성이 아닙니다. 표준은 열거 형의 값이 무엇인지 명시 적입니다.
MSalters
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.