C ++ 11에서 열거 형 클래스의 값을 어떻게 출력 할 수 있습니까?


96

enum classC ++ 11에서 의 값을 어떻게 출력 할 수 있습니까? C ++ 03에서는 다음과 같습니다.

#include <iostream>

using namespace std;

enum A {
  a = 1,
  b = 69,
  c= 666
};

int main () {
  A a = A::c;
  cout << a << endl;
}

C ++ 0x에서이 코드는 컴파일되지 않습니다.

#include <iostream>

using namespace std;

enum class A {
  a = 1,
  b = 69,
  c= 666
};

int main () {
  A a = A::c;
  cout << a << endl;
}


prog.cpp:13:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&'
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/ostream:579:5: error:   initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = A]'

Ideone.com 에서 편집


1
열거 형을 출력하려는 ​​이유는 무엇입니까? enum 클래스는 enum 값을 int 표현과 혼합하지 않는 데 사용됩니다
RiaD

답변:


122

범위가 지정되지 않은 열거와 달리 범위가 지정된 열거는 암시 적 으로 정수 값으로 변환 할 수 없습니다 . 캐스트를 사용하여 명시 적으로 정수로 변환 해야합니다 .

std::cout << static_cast<std::underlying_type<A>::type>(a) << std::endl;

논리를 함수 템플릿으로 캡슐화 할 수 있습니다.

template <typename Enumeration>
auto as_integer(Enumeration const value)
    -> typename std::underlying_type<Enumeration>::type
{
    return static_cast<typename std::underlying_type<Enumeration>::type>(value);
}

사용 :

std::cout << as_integer(a) << std::endl;

3
이것이 후행 반환 유형 구문을 사용하는 이유가 있습니까?
Nicol Bolas 2012

3
@NicolBolas : as_integer오픈 소스 라이브러리 중 하나 인 CxxReflect 에서 복사 했습니다 ( enumeration.hpp 참조 ). 라이브러리는 모든 곳에서 일관되게 후행 반환 유형을 사용합니다. 일관성을 위해.
James McNellis 2012

11
2 년이 늦었지만 다른 사람이이 질문을 볼 경우 위의 캐스트 기법을 사용하고 "static_cast <int> (value)"를 호출하여 정수를 가져 오거나 "static_cast <A> (intValue)"를 호출하여 열거 형 값을 얻습니다. int에서 enum으로 또는 enum에서 enum으로 이동하면 문제가 발생할 수 있으며 일반적으로 디자인 버그의 징후임을 명심하십시오.
Benjamin Danger Johnson

4
int (value) 및 A (intValue)도 못생긴 꺾쇠 괄호없이 작동합니다.
Grault

4
as_integerconstexpr상수 표현식이 필요한 컨텍스트에서 사용할 수 있도록 정의 할 수 있습니다.
Nawaz

39
#include <iostream>
#include <type_traits>

using namespace std;

enum class A {
  a = 1,
  b = 69,
  c= 666
};

std::ostream& operator << (std::ostream& os, const A& obj)
{
   os << static_cast<std::underlying_type<A>::type>(obj);
   return os;
}

int main () {
  A a = A::c;
  cout << a << endl;
}

이 예제를 그대로 복사하여 컴파일 g++ -std=c++0x enum.cpp했지만 컴파일러 오류-> pastebin.com/JAtLXan9 . 또한 @ james-mcnellis에서 예제를 컴파일 할 수 없습니다.
Dennis

4
@Dennis underlying_type는 단지 C ++에서 11
더칭

23

범위가 지정되지 않은 enum과 동일한 구문을 사용하여 작동하도록 두 번째 예제 (즉, 범위가 지정된 enum을 사용하는 예제)를 얻을 수 있습니다. 또한 솔루션은 일반적이며 모든 범위가 지정된 열거 형에 대해 작동하지만 각 범위가 지정된 열거 형에 대한 코드를 작성합니다 ( @ForEveR에서 제공 하는 답변 참조 ).

해결책은 operator<<범위가 지정된 열거 형에 대해 작동 하는 일반 함수 를 작성하는 것입니다. 이 솔루션은 SFINAE via를 사용 std::enable_if하며 다음과 같습니다.

#include <iostream>
#include <type_traits>

// Scoped enum
enum class Color
{
    Red,
    Green,
    Blue
};

// Unscoped enum
enum Orientation
{
    Horizontal,
    Vertical
};

// Another scoped enum
enum class ExecStatus
{
    Idle,
    Started,
    Running
};

template<typename T>
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e)
{
    return stream << static_cast<typename std::underlying_type<T>::type>(e);
}

int main()
{
    std::cout << Color::Blue << "\n";
    std::cout << Vertical << "\n";
    std::cout << ExecStatus::Running << "\n";
    return 0;
}

당신은 typename전에 필요합니다 std::underlying_type<T>::type.
uckelman

@uckelman 당신은 절대적으로 맞습니다. 내 답변을 업데이트 해 주셔서 감사합니다.
James Adkison

이것은 clang에서 나를 위해 일했지만 gcc 4.9.2에서는 오류와 함께 << 함께 연결할 때이 솔루션이 실패합니다 error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’. 이는 스트림이 일시적인 경우 ADL이 실패하고 위의 템플릿이 가능성이 없기 때문인 것으로 보입니다. 어떤 팁?
ofloveandhate 2015-09-14

@ofloveandhate 문제를 일으키는 예에 대한 링크를 제공 할 수 있습니까? gcc 4.9.2에서 위의 코드를 아무 문제없이 약간만 변경하여 테스트했으며 연산자를 함께 연결하여 3 개의 cout문을 단일 cout문 으로 변환했습니다 <<. 참조 여기
제임스 Adkison에게

내 진술을 수정하겠습니다. 클래스 외부에서 클래스 내부에 포함 된 열거 형 클래스를 인쇄하려고했습니다. 위의 코드는 실제로 클래스 자체에 포함되지 않은 열거 형 클래스에 대해 작동합니다.
ofloveandhate

10

(아직 언급 할 수 없습니다.) James McNellis의 이미 훌륭한 답변에 대해 다음과 같은 개선 사항을 제안합니다.

template <typename Enumeration>
constexpr auto as_integer(Enumeration const value)
    -> typename std::underlying_type<Enumeration>::type
{
    static_assert(std::is_enum<Enumeration>::value, "parameter is not of type enum or enum class");
    return static_cast<typename std::underlying_type<Enumeration>::type>(value);
}

  • constexpr: 컴파일 타임 배열 크기로 열거 형 멤버 값을 사용할 수 있습니다.
  • static_assert+ is_enum: 함수가 수행하는 컴파일 시간을 '보장'합니다. 제안 된대로 열거 형 만 사용

그건 그렇고 나는 스스로에게 묻고 있습니다 : enum class열거 형 멤버에 숫자 값을 할당하고 싶을 때 왜 사용해야합니까 ?! 전환 노력을 고려하십시오.

아마도 enum여기에서 제안한대로 평범한 상태 로 돌아갈 것 입니다. C ++에서 열거 형을 플래그로 사용하는 방법?


@TobySpeight의 제안에 따라 static_assert가없는 또 다른 (더 나은) 맛 :

template <typename Enumeration>
constexpr std::enable_if_t<std::is_enum<Enumeration>::value,
std::underlying_type_t<Enumeration>> as_number(const Enumeration value)
{
    return static_cast<std::underlying_type_t<Enumeration>>(value);
}

유형 거기에 T있는 std::underlying_type<T>::type존재하지만 std::is_enum<T>::value거짓은? 그렇지 않은 경우 static_assert값 이 추가되지 않습니다.
Toby Speight 2017

1
모든 컴파일러에서 테스트하지 않았습니다. 그러나 @TobySpeight가 맞을 것입니다 .msvc2013은 이해 가능한 오류 메시지를 뱉어내는 것 같습니다. 기존의 based_type_t와 유형 자체가 열거 형 사이의 일대일 대응을 제안합니다. 그리고 static_assert는 해고되지도 않습니다. 그러나 참조에 따르면 전체 열거 형 유형이 제공되지 않으면 기본 유형의 동작이 정의되지 않습니다. 따라서 static_assert는 경우에 대비하여 최대의 이해 가능한 메시지를 얻기위한 희망일뿐입니다. 아마도 더 일찍 / 가장 일찍 처리되도록 할 가능성이 있습니까?
yau

아 예, Enumeration완전한 enum 유형이 아닌 경우 정의되지 않은 것이 맞습니다 . 어떤 경우에는 반환 유형에 사용되므로 이미 너무 늦을 수 있습니다. 아마도 우리 std::enable_if<std::is_enum<Enumeration>::value, std::underlying_type<Enumeration>::type>는 반환 유형으로 지정할 수 있습니까? 물론, 그것은 너무 쉽게 (그리고 오류 메시지가 훨씬 명확하게) 당신은 개념을 지원하는 컴파일러가 있다면 ...
토비 Speight

6

더 간단하게 작성하려면

enum class Color
{
    Red = 1,
    Green = 11,
    Blue = 111
};

int value = static_cast<int>(Color::Blue); // 111

열거 형에 기본 유형이 명시 적으로 주어지면 작동하지 않습니다
James

3

다음은 C ++ 11에서 나를 위해 일했습니다.

template <typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value,
                                  typename std::underlying_type<Enum>::type>::type
to_integral(Enum const& value) {
    return static_cast<typename std::underlying_type<Enum>::type>(value);
}

0

다음과 같이 할 수 있습니다.

//outside of main
namespace A
{
    enum A
    {
        a = 0,
        b = 69,
        c = 666
    };
};

//in main:

A::A a = A::c;
std::cout << a << std::endl;

2
enum 클래스에 대해 질문했습니다.
Ant
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.