วิธีใช้ enums ใน 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
ฉันรู้ว่าฉันต้องการ o รู้ว่าทำไมมันทำให้ฉันมีข้อผิดพลาด!
Rika

1
วันพุธที่นี่ คุณมีข้อผิดพลาดทางไวยากรณ์มากเกินไปสำหรับคอมไพเลอร์ C ++ เริ่มต้นจาก 'Enum'
Öö Tiib

1
@Hossein เนื่องจาก enums ไม่ใช่ไวยากรณ์เดียวกัน (และซีแมนทิกส์) ในทั้งสองภาษา สิ่งแรกที่ฉันทำหลังจากได้รับข้อผิดพลาดเมื่อพยายามใช้คุณลักษณะในภาษาใหม่คือค้นหาไวยากรณ์ (หรือถ้าเป็นไปได้) ในภาษานั้น
chris

@ Chris: ฉันรู้ว่าฉันทำเช่นเดียวกันที่แน่นอน thing.hopefully ฉันได้ answer.I ของฉันยังมีการปรับปรุงคำถามให้มากขึ้น clearer.Thank คุณโดยวิธีการ;)
Rika

17
" เท่าที่ฉันรู้การประกาศและการใช้ enums ในสองภาษานี้เหมือนกัน ". มีปัญหาของคุณอยู่ที่นั่น C # ไม่ใช่ภาษาเดียวกันกับ C ++ โดยเฉพาะอย่างยิ่งพวกเขามีไวยากรณ์ที่แตกต่างกันสำหรับ enums
Robᵩ

คำตอบ:


350

รหัสนี้ผิด

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

เพราะDaysไม่ใช่ขอบเขตหรือวัตถุ มันเป็นประเภท และประเภทเองไม่มีสมาชิก std::string.clearสิ่งที่คุณเขียนเป็นเทียบเท่ากับ std::stringเป็นประเภทดังนั้นคุณจึงไม่สามารถใช้งาน.ได้ คุณใช้.กับอินสแตนซ์ของคลาส

น่าเสียดายที่ enums นั้นมีเวทย์มนตร์และการเปรียบเทียบก็หยุด เนื่องจากมีคลาสคุณสามารถทำได้std::string::clearเพื่อรับตัวชี้ไปยังฟังก์ชันสมาชิก แต่ใน C ++ 03 Days::Sundayไม่ถูกต้อง (อันไหนน่าเศร้า) นี่เป็นเพราะ C ++ เป็น (ค่อนข้าง) ย้อนกลับเข้ากันได้กับ C และ C ไม่มีเนมสเปซดังนั้นการแจกแจงจึงต้องอยู่ในเนมสเปซส่วนกลาง ดังนั้นไวยากรณ์จึงเป็นเพียง:

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

โชคดีที่ไมค์ซีมัวร์สังเกตว่าสิ่งนี้ได้รับการกล่าวถึงใน C ++ 11 เปลี่ยนenumเป็นenum classและได้รับขอบเขตของตัวเอง จึงDays::Sundayไม่ได้เป็นเพียงที่ถูกต้อง แต่เป็นเพียงSundayวิธีการที่จะเข้าถึง วันแห่งความสุข!


254
โชคดีที่การร้องเรียนของคุณได้รับการแก้ไขใน C ++ 11 เปลี่ยนenumเป็นenum classและได้รับขอบเขตของตัวเอง จึงDays::Sundayไม่ได้เป็นเพียงที่ถูกต้อง Sundayแต่เป็นวิธีที่จะเข้าถึงเฉพาะ วันแห่งความสุข!
Mike Seymour

11
ต้องรักข้อความแสดงข้อผิดพลาด C ++ ... พวกเขาพิสูจน์ว่าภาษานั้นยุ่งยากเกินไปที่จะให้ผลตอบรับที่ดี ฉันใช้มันว่า 'การแสดงออกหลัก' เป็นวัตถุหรือขอบเขตหรือสิ่งอื่น ๆ ที่ไม่ใช่ประเภท บางที Type เป็น 'Secondary-expression' และสิ่งที่ผู้พัฒนา C ++ อาจเรียกว่า 'ตัวดำเนินการแบบจุด' ตัวแปลภาษา C ++ สามารถเรียกได้ว่า 'โทเค็น' เท่านั้น เมื่อมันยากที่จะเข้าใจข้อความแสดงข้อผิดพลาดมีบางอย่างผิดปกติกับภาษาที่ฉันคิด
เทรวิส

4
@Travis: en.cppreference.com/w/cpp/language/… . การแสดงออกหลักเป็นเพียงสิ่งแรกในการแสดงออกมักจะชื่อหรือตัวแปรหรือตัวอักษร สำหรับส่วนที่สองฉันไม่เห็นความแตกต่างอย่างมากระหว่าง'.' tokenและdot operatorนอกเหนือจากมันเป็นโทเค็นและไม่ใช่ผู้ดำเนินการและมันแสดงสัญลักษณ์ที่แน่นอนมากกว่าชื่อ
Mooing Duck

@Mike Seymour ฉันพยายามเข้าถึง enums โดยไม่ต้องใช้ตัวแก้ไขความละเอียดของขอบเขตในคอมไพเลอร์มากมายและดูเหมือนว่าจะใช้งานได้ คุณพูดว่า C ++ 11 เป็นวิธีเดียวที่ฉันสามารถเข้าถึงค่า enum เป็น globals ได้ด้วยเหตุผลบางอย่างฉันไม่จำเป็นต้อง ::
Zebrafish

1
@TitoneMaurice: หากคุณมีenumคุณสามารถใช้ไม่มีขอบเขตหรือขอบเขตส่วนกลาง ( ::Saturday) หากคุณมีenum class(ซึ่งเป็นสิ่งที่แตกต่างกันมาก) แล้วคุณมีDays::Saturdayการใช้งาน
Mooing Duck

24

นี่จะเพียงพอที่จะประกาศตัวแปร enum ของคุณและเปรียบเทียบ:

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

ทำไมมันผิดที่จะบอกว่า (วัน == วันวันเสาร์) พวกเขาจะต้องเหมือนกันดังนั้นทำไมคอมไพเลอร์จึงบ่นเกี่ยวกับเรื่องนี้?
Rika

1
@Hossein ค่าที่ประกาศใน enum ของคุณจะไม่ทำงานเหมือนตัวแปรคลาสหรือ struct สมาชิก นี่ไม่ใช่ไวยากรณ์ที่ถูกต้องที่จะใช้
mathematician1975

2
@ โฮเซ่น: เพราะDaysไม่ใช่ขอบเขตหรือวัตถุ มันเป็นประเภท และประเภทเองไม่มีสมาชิก std::string.clearล้มเหลวในการรวบรวมด้วยเหตุผลเดียวกัน
Mooing Duck

8
@ โฮเซ่น: เพราะนั่นไม่ใช่วิธีการทำงานของ C ++ การแจกแจงแบบไม่มีขอบเขตจะใส่ค่าลงในเนมสเปซที่ล้อมรอบ คนขอบเขต ( enum classใหม่ในปี 2011) Days::Saturdayมีขอบเขตของตัวเองและมีการเข้าถึงการใช้ประกอบการขอบเขต โอเปอเรเตอร์การเข้าถึงสมาชิก ( .) ใช้เพื่อเข้าถึงสมาชิกคลาสเท่านั้น
Mike Seymour

@MooingDUck และ MikeSeymour พวกคุณหนึ่งคนจะโพสต์คำตอบของคุณเป็นคำตอบหรือไม่? เพราะนั่นคือสิ่งที่ผมหลังโดยการออกคำถามนี้;)
Rika

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 enum C ++ 11 ) พวกมันจะไม่ถูกห่อหุ้มเหมือนสมาชิกของวัตถุหรือโครงสร้างและ คุณไม่สามารถอ้างอิงถึงพวกเขาเป็นสมาชิก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;

ฉันมีการปรับปรุงคำถามที่ผมคิดว่าตอนนี้ชัดเจนว่าสิ่งที่ฉันว่าหลังจาก :) โดยวิธีการขอบคุณ :)
Rika

14

คุณสามารถใช้เคล็ดลับในการใช้ขอบเขตตามที่คุณต้องการเพียงประกาศ enum ในลักษณะดังกล่าว:

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

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

9

แทนที่จะใช้ข้อความสั่งจำนวนมาก enums ให้ยืมตัวเองได้ดีเพื่อสลับข้อความสั่ง

ฉันใช้การผสมผสาน enum / switch ในเครื่องมือสร้างเลเวลที่ฉันสร้างสำหรับเกมของฉัน

แก้ไข: อีกอย่างฉันเห็นว่าคุณต้องการไวยากรณ์ที่คล้ายกับ;

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;
}

สิ่งที่ดีที่นี่เป็นที่คอมไพเลอร์จะบอกคุณถ้าคุณพลาดการวางกรณีบอล.
คริส

คุณไม่ควรใช้คลาส enum ในกรณีนี้หรือไม่?
Rika

1
enum เป็นเพียงประเภทข้อมูลใน C ++ ดังนั้นการประกาศ enum เหมือนที่ฉันทำข้างบนในไฟล์. h และจากนั้นการรวมไฟล์นั้นในไฟล์. cpp ที่คุณต้องการใช้จะทำให้คุณเข้าถึง enum ได้ เพิ่งสังเกตเห็นฉันลืมที่จะเพิ่ม #include ในตัวอย่าง. cpp ของฉัน การแก้ไข
Dean Knight

นอกจากนี้ฉันเห็นคนอื่นบอกว่า enums ใน C ++ เป็นระดับโลก จากประสบการณ์ของฉันโดยใช้ enums ตามที่ฉันมีข้างต้นฉันสามารถเข้าถึงได้เฉพาะเมื่อฉันรวม. h ดังนั้นนี่ดูเหมือนจะหยุดการเข้าถึงทั่วโลกด้วยซึ่งก็ดีอยู่เสมอ แก้ไข: ดูเหมือนว่าฉันกำลังเป็นต้นเหตุของการใช้ enums ใน C ++ 11 วิธีถ้าฉันอ่านสิ่งที่ถูกต้อง ...
คณบดีอัศวิน

9

หากคุณยังคงใช้ C ++ 03 และต้องการใช้ enums คุณควรใช้ enums ภายในเนมสเปซ เช่น:

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

คุณสามารถใช้ enum นอกเนมสเปซเช่น

Daysofweek::Days day = Daysofweek::Saturday;

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

8

คุณกำลังมองหาenumerations พิมพ์ขอเป็นคุณสมบัติที่มีอยู่ใน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

การใช้::เป็น accessors to enumerations จะล้มเหลวหากกำหนดเป้าหมายมาตรฐาน C ++ ก่อน C ++ 11 แต่คอมไพเลอร์ตัวเก่าบางตัวไม่รองรับมันรวมถึง IDE บางตัวก็แค่แทนที่ตัวเลือกนี้และตั้งค่า C ++ std แบบเก่า

หากคุณกำลังใช้ GCC เปิดใช้งาน C + 11 พร้อมด้วย-std = C ++ 11หรือ-std = gnu11

มีความสุข!


1
enum class Days { ...คุณลืมที่จะเขียน
Martin Hennings

จริง แก้ไขมัน! ขอบคุณ
Alex Byrth

7

สิ่งนี้ไม่ควรทำงานใน C ++:

Days.Saturday

Days ไม่ใช่ขอบเขตหรือวัตถุที่มีสมาชิกที่คุณสามารถเข้าถึงด้วยตัวดำเนินการ dot ไวยากรณ์นี้เป็นเพียง C # -ism และไม่ถูกกฎหมายใน C ++

Microsoft ได้ปรับปรุงส่วนขยาย C ++ ที่ช่วยให้คุณเข้าถึงตัวระบุโดยใช้ตัวดำเนินการขอบเขต:

enum E { A, B, C };

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

แต่นี่ไม่ใช่มาตรฐานก่อนหน้า C ++ 11 ใน C ++ 03 ตัวระบุที่ประกาศใน enum นั้นมีอยู่ในขอบเขตเดียวกับชนิด enum เท่านั้น

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

C ++ 11 ทำให้ถูกต้องตามกฎหมายในการรับรองตัวระบุ enum ด้วยชื่อ enum และยังแนะนำคลาส enum ซึ่งสร้างขอบเขตใหม่สำหรับตัวระบุแทนการวางไว้ในขอบเขตโดยรอบ

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

enum class F { A, B, C };

A; // error
F::B;

4

น่าเศร้าองค์ประกอบของ enum คือ 'ทั่วโลก' day = Saturdayคุณสามารถเข้าถึงพวกเขาด้วยการทำ นั่นหมายความว่าคุณไม่สามารถenum A { a, b } ;และenum B { b, a } ;พวกเขากำลังขัดแย้ง


2
จนกว่าคุณจะใช้enum classใน C ++ 11 นั่นคือ ก่อนหน้านั้นคุณต้องสร้างคลาสหุ่น
chris

ไม่ทราบว่า C ++ 11 ฉันสมมติว่าคำถามหมายถึง C ++ ใช่การใช้คลาสหรือเนมสเปซจะทำการหลอกลวง
Grzegorz

@Grzegorz: ฉันคิดว่า chris หมายถึงคลาส enum ที่เพิ่งเปิดตัวใหม่ซึ่งให้ enums ที่พิมพ์อย่างมาก
Rika

@ โฮเซ่น: ขอบคุณสำหรับการชี้ให้เห็น ฉันพบคำอธิบายเกี่ยวกับชั้นเรียน NUM และฉันรู้ว่าสิ่งที่ Chris พูดถึง ขอบคุณมาก.
Grzegorz

@Grzegorz: ผมไม่ได้หมายถึงการไม่เคารพเพียงแค่คิดว่าฉันอาจจะช่วยขอโทษสำหรับความน่าจะเป็น misunderstanding.I ใด ๆ อีกครั้งขอขอบคุณสำหรับเวลาของคุณและช่วยฉัน;)
Rika

4

ในขณะที่ C ++ (ไม่รวม C ++ 11) มีจำนวน enums ค่าในพวกเขาจะ "leaked" ใน namespace ทั่วโลก
หากคุณไม่ต้องการให้รั่วไหลออกมา (และไม่จำเป็นต้องใช้ประเภท enum) ให้พิจารณาสิ่งต่อไปนี้:

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

3

Enums ใน C ++ เป็นเหมือนจำนวนเต็มซึ่งถูกปกปิดโดยชื่อที่คุณให้เมื่อคุณประกาศค่า enum ของคุณ (นี่ไม่ใช่คำจำกัดความเพียงคำใบ้ว่ามันทำงานอย่างไร)

แต่มีข้อผิดพลาดสองประการในรหัสของคุณ:

  1. สะกดenumตัวพิมพ์เล็กทั้งหมด
  2. คุณไม่ต้องการDays.ก่อนวันเสาร์
  3. ถ้า enum นี้ถูกประกาศในคลาสให้ใช้ 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 Daysและใช้ส่วนขยาย C ++ 03 + Microsoft หรือ C ++ 11
Futal

@Futal ข้างต้นวิ่งไปกับ Borland C ++ Builder Flavor / Version ของ C ++ ไม่ได้อยู่ในคำถาม
James Oravec

1
เวอร์ชันของ Borland C ++ Builder ของคุณต้องใช้ C ++ 11 หรือใหม่กว่า gcc และเสียงดังกราวทั้งให้ข้อผิดพลาดหรือคำเตือนถ้าตัวอย่างของคุณจะรวบรวมกับหรือ-std=c++98 เสียงดังกราวค่อนข้างชัดเจน:-std=c++03 warning: use of enumeration in a nested name specifier is a C++11 extension
Futal

1

ถ้าเราต้องการความปลอดภัยที่เข้มงวดและการกำหนดขอบเขตการใช้งานenum classนั้นดีใน C ++ 11

ถ้าเรามีการทำงานใน C ++ 98 เราสามารถใช้คำแนะนำที่ได้รับจากInitializeSahib, Sanการเปิดใช้งาน enum ขอบเขต

ถ้าเรายังต้องการความปลอดภัยที่เข้มงวดประเภทรหัสต่อไปนี้สามารถใช้ Somthing 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: Item 18


-15

ก่อนอื่นให้ 'E' แทน enum 'e' เป็นตัวพิมพ์เล็ก

ที่สองให้พิมพ์ชื่อแบบเลื่อนลง 'วัน' ใน 'Days.Saturday'

สาม ... ซื้อหนังสือ C ++ ที่ดีให้ตัวเอง


5
ขออภัยคุณได้รับคะแนนโหวตทั้งหมดเหล่านี้ (ฉันหมายความว่าคำตอบไม่สมควรได้รับ) แต่นั่นไม่ได้หมายความว่าคุณต้องออกจากชุมชนเป็นเวลา 6 ปี กลับมาและเข้าร่วมกับเรา คุณมีสิ่งที่จะมีส่วนร่วมด้วย เป็นประโยชน์ แบ่งปันความรู้
Gabriel Staples
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.