C ++에서 열거 형을 사용하는 방법


218

enum다음과 같은 것이 있다고 가정하십시오 .

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};

이 인스턴스를 만들고 enum적절한 값으로 초기화하고 싶습니다.

Days day = Days.Saturday;

이제 변수 또는 인스턴스를 기존 enum값 으로 확인하고 싶습니다 .

if (day == Days.Saturday)
{
    std::cout << "Ok its Saturday";
}

컴파일 오류가 발생합니다.

오류 : '.'이전에 예상 된 기본 표현식 토큰

분명히 말하자면, 말하기의 차이점은 무엇입니까?

if (day == Days.Saturday) // Causes compilation error

과

if (day == Saturday)

?

이 두 가지는 실제로 무엇을 의미합니까? 하나는 정상이고 하나는 컴파일 오류를 유발합니까?


4
나도 알아, 왜 그게 나에게 오류를 주는지 알고 싶다!
— Rika

1
수요일입니다. C ++ 컴파일러에 대한 구문 오류가 너무 많습니다. 'Enum'부터 시작합니다.
— Öö Tiib

1
@Hossein, 열거 형은 두 언어에서 동일한 구문 (및 의미론)이 아니기 때문입니다. 새 언어로 기능을 사용하려고 할 때 오류가 발생한 후 가장 먼저하는 일은 해당 언어의 구문을 찾아 보는 것입니다.
— chris

@ 크리스 : 나도 알아, 내가 정확한 thing.hopefully 난 내의 대답도 더 그런데 clearer.Thank 당신으로 질문을 업데이트있어 동일한 작업을 수행)
— 리카

17
" 이 두 언어의 enums 선언과 사용법은 동일합니다. ". 문제가 있습니다. C #은 C ++과 같은 언어 가 아닙니다 . 특히 열거 형의 구문이 다릅니다.
— Robᵩ

답변:


350

이 코드는 잘못되었습니다 :

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Days.Saturday;
if (day == Days.Saturday)

때문에 Days범위, 나 개체가 아닙니다. 타입입니다. 그리고 타입 자체에는 멤버가 없습니다. 당신이 쓴 것은에 해당합니다 std::string.clear. std::string유형이므로 사용할 수 없습니다 .. 클래스 .의 인스턴스 에서 사용 합니다 .

불행하게도, 열거 형은 마술이므로 유추가 그치지 않습니다. 클래스 std::string::clear를 사용하면 멤버 함수에 대한 포인터를 얻을 수 있지만 C ++ 03에서는 Days::Sunday유효하지 않습니다. (슬픈 것). 이것은 C ++이 C와 호환되는 (뒤로) 역행 성이기 때문에 C는 네임 스페이스가 없기 때문에 열거는 전역 네임 스페이스에 있어야했기 때문입니다. 따라서 구문은 다음과 같습니다.

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday)

다행스럽게도 Mike Seymour 는 이것이 C ++ 11에서 해결되었음을 관찰합니다. 변경 enum에 enum class그것의 자신의 범위를 얻고; 따라서 Days::Sunday유효 할 뿐만 아니라 에 액세스 할 수 있는 유일한 방법 Sunday입니다. 행복한 날들!


254
다행스럽게도 귀하의 불만은 C ++ 11에서 해결되었습니다. 변경 enum에 enum class그것의 자신의 범위를 얻고; 따라서 Days::Sunday유효 할뿐만 아니라에 액세스 할 수있는 유일한 방법 Sunday입니다. 행복한 날들!
— Mike Seymour

11
C ++ 오류 메시지를 좋아해야합니다 ... 언어가 좋은 피드백을 제공하기 위해 번거 롭다는 것을 증명합니다. '1 차 표현'은 객체 또는 범위 또는 유형이 아닌 다른 것입니다. 아마도 Type은 'secondary-expression'일 것입니다. 그리고 C ++ 개발자가 '도트 연산자'라고 부르는 것은 C ++ 컴파일러는 '토큰'만 호출 할 수 있습니다. 오류 메시지를 이해하기가 어려워지면 내가 생각하는 언어에 문제가 있습니다.
— 트래비스

4
@Travis : en.cppreference.com/w/cpp/language/… . 기본 표현식은 표현식에서 첫 번째로, 일반적으로 이름 또는 변수 또는 리터럴입니다. 두 번째 부분 은 토큰이 아니라 연산자가 아닌 '.' tokenand와 큰 차이가 dot operator없으며 이름이 아닌 정확한 기호를 보여줍니다.
— Mooing Duck

@ Mike Seymour 나는 많은 컴파일러에서 스코프 해상도 연산자없이 열거 형에 액세스하려고 시도했지만 작동하는 것 같습니다. 당신은이 :: 필요하지 않습니다, 난 그냥 전역으로 열거 값에 액세스 할 수있는 몇 가지 이유있는 유일한 방법 (11) C ++의로 말했다
— Zebrafish의

1
@TitoneMaurice :가있는 경우 enum범위를 사용하지 않거나 전역 범위 ( ::Saturday)를 사용할 수 없습니다 . 당신이있는 경우 enum class(매우 다른 것 인), 당신은 이 사용 Days::Saturday.
— Mooing Duck

24

이것은 열거 형 변수를 선언하고 비교하기에 충분합니다.

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday) {
    std::cout << "Ok its Saturday";
}

if (day == Days.Satudday)라고 말하는 것이 왜 잘못 되었습니까? 그들은 동일해야합니다. 왜 컴파일러가 그것에 대해 불평합니까?
— Rika

1
@Hossein 열거 형에 선언 된 값은 클래스 또는 구조체 멤버 변수처럼 작동하지 않습니다. 이것은 올바른 구문이 아닙니다
— 수학자

2
@Hossein : Days범위도 아니고 개체도 아니기 때문 입니다. 타입입니다. 그리고 유형 자체 에는 멤버가 없습니다. std::string.clear같은 이유로 컴파일하지 못합니다.
— Mooing Duck

8
@ Hossein : C ++의 열거 형이 작동하지 않기 때문입니다. 범위가 지정되지 않은 열거는 값을 주변 네임 스페이스에 넣습니다. 범위가 지정된 항목 ( enum class, 2011의 새로운 기능)에는 자체 범위가 있으며 범위 연산자를 사용하여 액세스합니다 Days::Saturday. 멤버 액세스 연산자 ( .)는 클래스 멤버에 액세스하는 데만 사용됩니다.
— Mike Seymour

@MooingDUck and MikeSeymour 여러분 중 한 명이 답변으로 답변을 게시 하시겠습니까? 그것이
— 바로이

22

이 중 많은 부분에 컴파일 오류가 발생합니다.

// note the lower case enum keyword
enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday };

이제 Saturday, Sunday등 최상위 베어 상수로 사용할 수 있고, Days형태로 사용할 수 있습니다 :

Days day = Saturday;   // Days.Saturday is an error

그리고 마찬가지로 나중에 테스트하려면 다음을 수행하십시오.

if (day == Saturday)
    // ...

이들 enum 그들이있는 거 - 값은 베어 상수처럼 유엔 (당신이 C ++ (11) 사용하지 않는 : 컴파일러에서 약간의 여분의 도움으로 - -scoped 열거 클래스 가) 없습니다 예를 들어 개체 또는 구조 멤버와 같이 캡슐화하고, 님을 회원 으로 참조 할 수 없습니다 Days.

당신은 당신이 찾고있는 무엇을해야 C ++ 11 소개 enum class:

enum class Days
{
    SUNDAY,
    MONDAY,
    // ... etc.
}

// ...

if (day == Days::SUNDAY)
    // ...

이 C ++는 몇 가지면에서 C와 약간 다릅니다. 하나는 C를 사용해야한다는 것입니다. enum 변수를 선언 할 때 키워드를 .

// day declaration in C:
enum Days day = Saturday;

내가 생각하는 질문을 업데이트 한 그 내가 정확히 후거야 어떤 :) 그런데 감사합니다 :)으로 지금 명확
— 리카

14

원하는대로 범위를 사용하는 트릭을 사용할 수 있습니다. enum을 다음과 같이 선언하면됩니다.

struct Days 
{
   enum type
   {
      Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday
   };
};

Days::type day = Days::Saturday;
if (day == Days::Saturday)

9

많은 if 문을 사용하는 대신 열거 형은 문장을 전환하는 데 적합합니다.

게임용으로 빌드하는 레벨 빌더에서 일부 열거 / 스위치 조합을 사용합니다.

편집 : 또 다른 것은 비슷한 구문을 원한다는 것을 알 수 있습니다.

if(day == Days.Saturday)
etc

C ++에서이를 수행 할 수 있습니다.

if(day == Days::Saturday)
etc

다음은 매우 간단한 예입니다.

EnumAppState.h

#ifndef ENUMAPPSTATE_H
#define ENUMAPPSTATE_H
enum eAppState
{
    STARTUP,
    EDIT,
    ZONECREATION,
    SHUTDOWN,
    NOCHANGE
};
#endif

Somefile.cpp

#include "EnumAppState.h"
eAppState state = eAppState::STARTUP;
switch(state)
{
case STARTUP:
    //Do stuff
    break;
case EDIT:
    //Do stuff
    break;
case ZONECREATION:
    //Do stuff
    break;
case SHUTDOWN:
    //Do stuff
    break;
case NOCHANGE:
    //Do stuff
    break;
}

여기서 좋은 점은 케이스를 넣지 못한 경우 컴파일러가 알려줄 것입니다.
— chris

이 경우 클래스 열거 형을 사용해야합니까?
— Rika

1
enum은 C ++의 데이터 유형 일 뿐이므로 위에서 .h 파일에서 열거 한 것처럼 enum을 선언 한 다음 사용하려는 .cpp 파일에 해당 파일을 포함하면 enum에 액세스 할 수 있습니다. 내 .cpp 예제에 #include를 추가하는 것을 잊어 버렸습니다. 편집.
— Dean Knight

또한 C ++의 열거 형이 전역 적이라고 말하는 다른 사람이 있습니다. 내 경험상 위와 같은 방법으로 열거 형을 사용하면 .h를 포함시킨 경우에만 액세스 할 수 있습니다. 따라서 이것은 전역 액세스도 중지하는 것처럼 보이며 항상 좋습니다. 편집 : 제대로 읽고 올바르게 C ++ 11 방식으로 열거 형을 사용하고있는 것 같습니다 ...
— Dean Knight

9

여전히 C ++ 03을 사용하고 열거 형을 사용하려면 네임 스페이스 내에서 열거 형을 사용해야합니다. 예 :

namespace Daysofweek{
enum Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
}

네임 스페이스 외부에서 열거 형을 사용할 수 있습니다.

Daysofweek::Days day = Daysofweek::Saturday;

if (day == Daysofweek::Saturday)
{
    std::cout<<"Ok its Saturday";
}

8

C ++ 11 에서 사용할 수있는 강력한 형식의 열거 형을 찾고 있습니다. 표준 있습니다. 열거를 범위 값이있는 클래스로 바꿉니다.

자신의 코드 예제를 사용하면 다음과 같습니다.

  enum class Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
  Days day = Days::Saturday;

  if (day == Days::Saturday)  {
    cout << " Today is Saturday !" << endl;
  }
  //int day2 = Days::Sunday; // Error! invalid

::C ++ 표준 이전 C ++ 11을 대상으로하는 경우 접근자를 열거 자로 사용 하면 실패합니다. 그러나 일부 오래된 컴파일러는 지원하지 않으며 일부 IDE는이 옵션을 무시하고 오래된 C ++ 표준을 설정합니다.

GCC를 사용하는 경우 -std = c ++ 11 또는 -std = gnu11로 C + 11을 활성화 하십시오 .

행복하세요!


1
당신은 쓰는 것을 잊었다 enum class Days { ....
— Martin Hennings 2014 년

과연. 그것을 고쳐라! 감사.
— Alex Byrth

7

C ++에서는 작동하지 않습니다.

Days.Saturday

요일은 도트 연산자로 액세스 할 수있는 멤버가 포함 된 범위 나 개체가 아닙니다. 이 구문은 단지 C # -ism이며 C ++에서는 유효하지 않습니다.

Microsoft는 범위 연산자를 사용하여 식별자에 액세스 할 수있는 C ++ 확장을 오랫동안 유지해 왔습니다.

enum E { A, B, C };

A;
E::B; // works with Microsoft's extension

그러나 이것은 C ++ 11 이전의 비표준입니다. C ++ 03에서는 열거 형에 선언 된 식별자가 열거 형 자체와 동일한 범위에만 존재합니다.

A;
E::B; // error in C++03

C ++ 11은 열거 형 식별자를 열거 형 이름으로 한정하는 것이 합법적이며, 열거 형 클래스를 도입하여 식별자를 주변 범위에 배치하는 대신 새로운 범위를 만듭니다.

A;
E::B; // legal in C++11

enum class F { A, B, C };

A; // error
F::B;

4

안타깝게도 열거 형의 요소는 '전역'입니다. 를 통해 액세스 할 수 있습니다 day = Saturday. 그것은 당신이 가질 수없고 그들이 갈등을 enum A { a, b } ;하고 있다는 것을 의미합니다 enum B { b, a } ;.


2
enum classC ++ 11에서 사용할 때까지는 그렇습니다 . 그 전에 더미 수업을 만들어야합니다.
— chris

C ++ 11을 모른다. 질문이 C ++에 관한 것이라고 가정합니다. 예, 클래스 나 네임 스페이스를 사용하면 트릭을 수행 할 수 있습니다.
— Grzegorz

@ Grzegorz : chris는 새로 입력 된 열거 형 클래스를 참조한다고 생각합니다.
— Rika

@ 호세인 : 지적 해 주셔서 감사합니다. 나는 num 클래스에 대한 설명을 찾았고 Chris가 무엇에 관해 이야기하고 있는지 알고 있습니다. 고마워
— Grzegorz

@Grzegorz : 무례 함을 의미하지는 않았으며, 단지 내가 오해하고 있을지도 모른다는 생각에 오해가있어 유감스럽게 생각했다. 시간을 내 주셔서 감사합니다.)
— Rika

4

C ++ (C ++ 11 제외)에는 열거 형이 있지만 그 값은 전역 네임 스페이스에 "누설"됩니다.
누수를 원하지 않으면 (그리고 열거 형을 사용할 필요가 없다면) 다음을 고려하십시오.

class EnumName {  
   public:   
      static int EnumVal1;  
      (more definitions)  
};  
EnumName::EnumVal1 = {value};  
if ([your value] == EnumName::EnumVal1)  ...

3

C ++의 열거 형은 열거 형 값을 선언 할 때 주어진 이름으로 마스크 된 정수와 같습니다 (이것은 작동 방식에 대한 힌트 일뿐입니다).

그러나 코드에는 두 가지 오류가 있습니다.

  1. enum모든 소문자 철자
  2. Days.토요일 이전 에는 필요하지 않습니다 .
  3. 이 열거 형이 클래스에서 선언 된 경우 if (day == YourClass::Saturday){}

OP는 초기 게시물 16 분 후 철자 / 사례를 변경했습니다 ( 개정 1 에서 개정 2 ).
— Peter Mortensen

1

루트 문제는의 .대신 ::네임 스페이스를 사용하는 것입니다.

시험:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Days::Saturday;
if(Days::Saturday == day)  // I like literals before variables :)
{
    std::cout<<"Ok its Saturday";
}

Days::예제에서와 같이 범위 를 사용하려면 열거를 정의하고 enum class DaysC ++ 03 + Microsoft 확장 또는 C ++ 11을 사용해야합니다.
— Futal

@Futal은 위의 Borland C ++ Builder에서 실행되었습니다. C ++의 Flavor / Version은 문제가되지 않습니다.
— James Oravec

1
Borland C ++ Builder 버전은 C ++ 11 이상을 사용해야합니다. Gcc와 Clang은 예제가 -std=c++98또는 로 컴파일되면 오류 또는 경고를 표시합니다 -std=c++03. Clang은 매우 분명합니다 : warning: use of enumeration in a nested name specifier is a C++11 extension.
— Futal

1

엄격한 타입 안전과 범위가 지정된 열거 형을 원하면 enum classC ++ 11에서 사용하는 것이 좋습니다.

우리가 98 C ++로 작업해야한다면, 우리는에 의해 주어진 조언을 사용하여 수 InitializeSahib, San범위가 지정된 열거를 활성화합니다.

엄격한 타입 안전성을 원한다면 다음 코드는와 같은 것을 구현할 수 있습니다 enum.

#include <iostream>
class Color
{
public:
    static Color RED()
    {
        return Color(0);
    }
    static Color BLUE()
    {
        return Color(1);
    }
    bool operator==(const Color &rhs) const
    {
        return this->value == rhs.value;
    }
    bool operator!=(const Color &rhs) const
    {
        return !(*this == rhs);
    }

private:
    explicit Color(int value_) : value(value_) {}
    int value;
};

int main()
{
    Color color = Color::RED();
    if (color == Color::RED())
    {
        std::cout << "red" << std::endl;
    }
    return 0;
}

이 코드는 Effective C ++ 3rd 책의 Month 클래스 예제에서 수정되었습니다.


-15

우선, 'E'를 열거 형으로, 'e'를 소문자로 만듭니다.

둘째, 'Days.Saturday'에 유형 이름 'Days'를 놓으십시오.

셋째 ... 좋은 C ++ 책을 사십시오.


5
유감스럽게도 이러한 다운 투표권을 모두 얻었지만 (정답은 그만한 가치가 있습니다.) 그렇다고 6 년 동안 커뮤니티를 떠나야하는 것은 아닙니다. 돌아와서 우리와 함께 당신도 기여할 것이 있습니다. 도움이 되길. 지식을 공유하십시오.
— Gabriel Staples 19
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.