C ++ 열거 형 클래스의 요소 수를 확인할 수 있습니까? D, E }; 을

그것은 C ++의 중요도를 결정하는 것이 가능하다 enum class:

enum class Example { A, B, C, D, E };

을 사용하려고했지만 sizeof열거 형 요소의 크기를 반환합니다.

sizeof(Example); // Returns 4 (on my architecture)

카디널리티를 얻는 표준 방법이 있습니까 (예에서는 5)?



답변

직접적으로는 아니지만 다음 트릭을 사용할 수 있습니다.

enum class Example { A, B, C, D, E, Count };

그런 다음 카디널리티를 static_cast<int>(Example::Count).

물론 이것은 열거 형의 값을 0부터 자동으로 할당하는 경우에만 잘 작동합니다. 그렇지 않은 경우 Count에 올바른 카디널리티를 수동으로 할당 할 수 있습니다. 이는 별도의 상수를 유지해야하는 것과 다르지 않습니다. 어쨌든:

enum class Example { A = 1, B = 2, C = 4, D = 8, E = 16, Count = 5 };

한 가지 단점은 컴파일러가 Example::Count열거 형 값에 대한 인수 로 사용할 수 있도록 허용한다는 것입니다. 따라서 이것을 사용하는 경우주의하십시오! (나는 개인적으로 이것이 실제로 문제가되지 않는다고 생각한다.)


답변

C ++ 17의 경우 magic_enum::enum_countlib https://github.com/Neargye/magic_enum 에서 사용할 수 있습니다 .

magic_enum::enum_count<Example>() -> 4.

단점은 어디에 있습니까?

이 라이브러리는 Clang> = 5, MSVC> = 15.3 및 GCC> = 9에서 작동 하는 컴파일러 관련 해킹 ( __PRETTY_FUNCTION__/ 기반 __FUNCSIG__)을 사용합니다.

주어진 간격 범위를 살펴보고 이름이있는 모든 열거를 찾습니다. 이것이 카운트가됩니다. 제한 사항 에 대해 자세히 알아보기

이 해킹에 대한 자세한 내용은이 게시물 https://taylorconor.com/blog/enum-reflection .


답변

constexpr auto TEST_START_LINE = __LINE__;
enum class TEST { // Subtract extra lines from TEST_SIZE if an entry takes more than one 
    ONE = 7
  , TWO = 6
  , THREE = 9
};
constexpr auto TEST_SIZE = __LINE__ - TEST_START_LINE - 3;

이것은 UglyCoder의 답변 에서 파생 되었지만 세 가지 방법으로 개선되었습니다.

  • type_safe 열거 형 ( BEGINSIZE) 에는 추가 요소가 없습니다 ( Cameron의 대답 에도이 문제가 있습니다.)
    • 컴파일러는 switch 문에서 누락되었다고 불평하지 않습니다 (중요한 문제).
    • 열거 형을 예상하는 함수에 실수로 전달할 수 없습니다. (일반적인 문제가 아님)
  • 사용을 위해 주조 할 필요가 없습니다. ( Cameron의 대답에도이 문제가 있습니다.)
  • 빼기는 enum 클래스 유형의 크기를 엉망으로 만들지 않습니다.

열거 자에 임의의 값을 할당 할 수 있다는 Cameron의 대답에 비해 UglyCoder의 이점을 유지 합니다.

문제는 ( UglyCoder 와 공유 하지만 Cameron 과는 공유 하지 않음 ) 개행과 주석을 중요하게 만든다는 것입니다. 따라서 누군가는 TEST_SIZE의 계산 을 조정하지 않고 공백이나 주석이있는 항목을 추가 할 수 있습니다 .


답변

enum class TEST
{
    BEGIN = __LINE__
    , ONE
    , TWO
    , NUMBER = __LINE__ - BEGIN - 1
};

auto const TEST_SIZE = TEST::NUMBER;

// or this might be better 
constexpr int COUNTER(int val, int )
{
  return val;
}

constexpr int E_START{__COUNTER__};
enum class E
{
    ONE = COUNTER(90, __COUNTER__)  , TWO = COUNTER(1990, __COUNTER__)
};
template<typename T>
constexpr T E_SIZE = __COUNTER__ - E_START - 1;

답변

X () 매크로를 기반으로하는 한 가지 트릭이 있습니다. 이미지에는 다음과 같은 열거 형이 있습니다.

enum MyEnum {BOX, RECT};

다음으로 다시 포맷하십시오.

#define MyEnumDef \
    X(BOX), \
    X(RECT)

그런 다음 다음 코드는 열거 형 유형을 정의합니다.

enum MyEnum
{
#define X(val) val
    MyEnumDef
#undef X
};

다음 코드는 열거 형 요소의 수를 계산합니다.

template <typename ... T> void null(T...) {}

template <typename ... T>
constexpr size_t countLength(T ... args)
{
    null(args...); //kill warnings
    return sizeof...(args);
}

constexpr size_t enumLength()
{
#define XValue(val) #val
    return countLength(MyEnumDef);
#undef XValue
}

...
std::array<int, enumLength()> some_arr; //enumLength() is compile-time
std::cout << enumLength() << std::endl; //result is: 2
...

답변

시도 할 수있는 한 가지 트릭은 목록 끝에 열거 형 값을 추가하고이를 크기로 사용하는 것입니다. 귀하의 예에서

enum class Example { A, B, C, D, E, ExampleCount };

답변

boost의 전 처리기 유틸리티를 사용하는 경우 다음을 사용하여 개수를 얻을 수 있습니다. BOOST_PP_SEQ_SIZE(...) .

예를 들어 CREATE_ENUM다음과 같이 매크로를 정의 할 수 있습니다.

#include <boost/preprocessor.hpp>

#define ENUM_PRIMITIVE_TYPE std::int32_t

#define CREATE_ENUM(EnumType, enumValSeq)                                  \
enum class EnumType : ENUM_PRIMITIVE_TYPE                                  \
{                                                                          \
   BOOST_PP_SEQ_ENUM(enumValSeq)                                           \
};                                                                         \
static constexpr ENUM_PRIMITIVE_TYPE EnumType##Count =                     \
                 BOOST_PP_SEQ_SIZE(enumValSeq);                            \
// END MACRO   

그런 다음 매크로를 호출합니다.

CREATE_ENUM(Example, (A)(B)(C)(D)(E));

다음 코드를 생성합니다.

enum class Example : std::int32_t
{
   A, B, C, D, E
};
static constexpr std::int32_t ExampleCount = 5;

이것은 부스트 ​​전 처리기 도구와 관련하여 표면을 긁는 것입니다. 예를 들어, 매크로는 강력한 형식의 열거 형에 대한 문자열 변환 유틸리티 및 ostream 연산자를 정의 할 수도 있습니다.

부스트 전 처리기 도구에 대한 자세한 내용은
https://www.boost.org/doc/libs/1_70_0/libs/preprocessor/doc/AppendixA-AnIntroductiontoPreprocessorMetaprogramming.html


제쳐두고, 나는 Count수락 된 답변에 사용 된 추가 열거 값이 switch문을 사용하는 경우 컴파일러 경고 두통 을 유발할 것이라는 @FantasticMrFox에 강력하게 동의 합니다. unhandled case더 안전한 코드 유지 관리에 컴파일러 경고가 매우 유용하다는 것을 알게 되었으므로이를 훼손하고 싶지 않습니다.