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에서 해결되었음을 관찰합니다. 변경 enumenum class그것의 자신의 범위를 얻고; 따라서 Days::Sunday유효 할 뿐만 아니라 에 액세스 할 수 있는 유일한 방법 Sunday입니다. 행복한 날들!


254
다행스럽게도 귀하의 불만은 C ++ 11에서 해결되었습니다. 변경 enumenum 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.