() ฉันจะนับรายการใน enum ได้อย่างไร?


98

คำถามนี้เกิดขึ้นในใจของฉันเมื่อฉันมีบางอย่างเช่น

enum Folders {FA, FB, FC};

และต้องการสร้างอาร์เรย์ของคอนเทนเนอร์สำหรับแต่ละโฟลเดอร์:

ContainerClass*m_containers[3];
....
m_containers[FA] = ...; // etc.

(การใช้แผนที่มันสวยงามกว่ามากที่จะใช้std::map<Folders, ContainerClass*> m_containers;:)

แต่เพื่อกลับไปที่คำถามเดิมของฉัน: ถ้าฉันไม่ต้องการฮาร์ดโค้ดขนาดอาร์เรย์จะมีวิธีคิดว่ามีกี่รายการในโฟลเดอร์หรือไม่? (โดยไม่ต้องอาศัยเช่นFCเป็นรายการสุดท้ายในรายการซึ่งจะอนุญาตบางอย่างเช่นContainerClass*m_containers[FC+1]ถ้าฉันจำไม่ผิด


โพสต์นี้อาจตอบคำถามของคุณ: stackoverflow.com/questions/1390703/enumerate-over-an-enum-in-c
StackedCrooked

1
คำถามค่อนข้างไม่ชัดเจน ตามมาตรฐาน C ++ int(FA) | int(FB) | int (FC)ยังเป็นค่าทางกฎหมายสำหรับFoldersตัวแปร หากคุณปรับขนาดm_containersเพื่อให้Foldersตัวแปรใด ๆเป็นดัชนีที่ถูกต้อง[FC+1]จะไม่ใหญ่พอ
MSalters

ฉันได้ถามสิ่งที่เกี่ยวข้องมากบนstackoverflow.com/questions/12972317/count-on-enum-c-automatic
sergiol

ฉันขอแนะนำวิธีแก้ปัญหาจากstackoverflow.com/a/60216003/12894563และตัวแปรที่ปรับปรุงจากstackoverflow.com/a/60271408/12894563
ixjxk

คำตอบ:


123

ไม่มีวิธีที่ดีในการทำเช่นนี้โดยปกติคุณจะเห็นรายการพิเศษใน enum นั่นคือ

enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};

ดังนั้นคุณสามารถทำได้:

int fuz[FOOBAR_NR_ITEMS];

ยังไม่ค่อยดีนัก

แต่แน่นอนว่าคุณตระหนักดีว่าจำนวนสิ่งของใน enum นั้นไม่ปลอดภัยเช่น

enum foobar {foo, bar = 5, baz, quz = 20};

จำนวนรายการจะเป็น 4 แต่ค่าจำนวนเต็มของค่า enum จะไม่อยู่ในช่วงดัชนีอาร์เรย์ การใช้ค่า enum สำหรับการจัดทำดัชนีอาร์เรย์ไม่ปลอดภัยคุณควรพิจารณาตัวเลือกอื่น ๆ

แก้ไข: ตามที่ร้องขอทำให้รายการพิเศษโดดเด่นมากขึ้น


27
เรียกมันว่า LAST หรือ ALWAYS_AT_END หรือสิ่งที่ไม่คลุมเครือ ทำให้มันติดออก เพื่อไม่ให้ผู้ดูแลคนต่อไปเพิ่มรายการใหม่โดยไม่ได้ตั้งใจหลังจากที่คุณสิ้นสุดเครื่องหมาย
Martin York

3
ไม่ว่าจะดีขึ้นหรือแย่ลงนี่คือแนวทางที่เราใช้ในองค์กรของเรา ปกติเราเรียกว่า FINAL_enumname_ENTRY เช่น FINAL_foobar_ENTRY ฉันยังเคยเห็นผู้คนใช้ตัวแปร FOOBAR_COUNT แบบคงที่ที่แยกจากกันซึ่งกำหนดไว้ทันทีหลังจากการประกาศ enum ซึ่งเป็นวิธีการที่มีข้อผิดพลาดมากกว่าเล็กน้อย
Darryl

1
อย่างน้อยก็ค่อนข้างง่ายที่จะเห็นว่า "enum foo {a = 10, LAST}" จะเป็นเลขคี่ และฉันคิดว่า "int arr [LAST]" จะเป็น 11 รายการในกรณีนี้ไม่ใช่ 2 ดังนั้นโค้ดส่วนใหญ่จะใช้งานได้ (แต่คุณกำลังเสียหน่วยความจำกับค่าดัชนีที่ไม่ถูกต้อง)
Code Abominator

32

สำหรับ C ++ มีเทคนิค enum ประเภทปลอดภัยหลายแบบและบางส่วน (เช่นBoost.Enum ที่เสนอ แต่ไม่เคยส่ง) รวมถึงการสนับสนุนในการรับขนาดของ enum

แนวทางที่ง่ายที่สุดซึ่งใช้ได้กับ C และ C ++ คือใช้หลักการประกาศค่า ... MAX สำหรับ enum แต่ละประเภทของคุณ:

enum Folders { FA, FB, FC, Folders_MAX = FC };
ContainerClass *m_containers[Folders_MAX + 1];
....
m_containers[FA] = ...; // etc.

แก้ไข : เกี่ยว{ FA, FB, FC, Folders_MAX = FC}กับกับ{FA, FB, FC, Folders_MAX]: ฉันชอบตั้งค่า ... MAX เป็นมูลค่าทางกฎหมายสุดท้ายของ enum ด้วยเหตุผลบางประการ:

  1. ชื่อของค่าคงที่มีความแม่นยำมากขึ้นในทางเทคนิค (เนื่องจากFolders_MAXให้ค่า enum สูงสุดที่เป็นไปได้)
  2. โดยส่วนตัวแล้วฉันรู้สึกว่าFolders_MAX = FCโดดเด่นกว่ารายการอื่น ๆ อีกเล็กน้อย (ทำให้ยากขึ้นเล็กน้อยที่จะเพิ่มค่า enum โดยไม่ได้ตั้งใจโดยไม่ต้องอัปเดตค่าสูงสุดซึ่งเป็นปัญหาที่ Martin York อ้างถึง)
  3. GCC มีคำเตือนที่เป็นประโยชน์เช่น "ค่าการแจงนับไม่รวมอยู่ในสวิตช์" สำหรับรหัสดังต่อไปนี้ การปล่อยให้ Folders_MAX == FC + 1 ทำลายคำเตือนเหล่านั้นเนื่องจากคุณจบลงด้วยค่าการแจงนับจำนวน ... MAX ที่ไม่ควรรวมอยู่ในสวิตช์
สวิตช์ (โฟลเดอร์) 
{
  กรณี FA: ... ;
  case FB: ... ;
  // อ๊ะลืม FC!
}

3
ทำไมไม่ทำ: enum Folders { FA, FB, FC, Folders_MAX }; ContainerClass *m_containers[Folders_MAX];?
บิล

1
ฉันอยากจะบอกให้ชัดเจนว่าสุดท้ายคือตัวเลขและพวกเขาทั้งหมดมีชื่อเดียวกันต้องขอบคุณ:struct SomeEnum { enum type {FA, FB, FC, NB__};};
Luc Hermitte

2
อันที่จริงฉันรู้สึกว่าคำเตือนที่ "เป็นประโยชน์" เหล่านั้นเป็นความเจ็บปวดที่ตูด ฉันชอบคำเตือนที่ดีฉันมักจะตั้งค่า -Wall -pedantic ฯลฯ เมื่อฉันกำลังพัฒนา แต่คำเตือนเหล่านี้มันโง่มาก มีเพียงไม่กี่ที่แย่กว่านั้นเช่นแนะนำ parens สำหรับ && || และ & ^ | ลำดับความสำคัญของตัวดำเนินการ ฉันหมายความว่าฉันคิดว่า Java เป็นภาษาเลี้ยง, สิ่งที่นรกที่เกิดขึ้นกับ C และ C ++ ...

2
ข้อเสียของการมี Folders_max = FC คือคุณต้องเปลี่ยนทุกครั้งที่คุณเพิ่มบางสิ่งลงใน enum!
Étienne

2
โฟลเดอร์ enum {FA, FB, FC, Folders_MIN = FA, Folders_MAX = FC}; เพียงเพื่อเน้นย้ำว่ามันมีประโยชน์สำหรับการทำซ้ำ?
gjpc

7

ลักษณะนิสัยในแบบ STL เป็นอย่างไร? ตัวอย่างเช่น:

enum Foo
{
    Bar,
    Baz
};

เขียนไฟล์

std::numeric_limits<enum Foo>::max()

ความเชี่ยวชาญ (อาจเป็น constexpr ถ้าคุณใช้ c ++ 11) จากนั้นในรหัสทดสอบของคุณให้การยืนยันแบบคงที่เพื่อรักษาข้อ จำกัด ที่ std :: numeric_limits :: max () = last_item


2
น่าเสียดายที่การดำเนินการนี้ใช้ไม่ได้ตามคำตอบนี้
rr-

3
std::numeric_limits<enum Foo>::max()จะคืนค่าศูนย์เสมอ ... (ดูคำถามสำหรับคำตอบที่เชื่อมโยง) ทดสอบกับ enums ปกติ ( enum Foo { ... }), enums คำenum class Foo : uint8_t { ... }ใบ้ประเภท ( ) ด้วย gcc 5.2.0 @ Linux และ MinGW 4.9.3 @ Windows
rr-

1
(... และในกรณีนี้std::numeric_limits<std::underlying_type<Foo>::type>::max()จะส่งคืนค่าสูงสุดของชนิดพื้นฐานเช่น 0xFFFFFFFF สำหรับจำนวนเต็ม 32 บิตซึ่งไม่มีประโยชน์ในบริบทนี้)
rr-

1
แปลกเพราะฉันมีรหัสที่ใช้งานได้ซึ่งทำตามที่อธิบายไว้ namespace gx { enum struct DnaNucleobase : char { A, C, G, T }; } จากนั้น: namespace std { template<> struct numeric_limits<enum ::gx::DnaNucleobase> { typedef enum ::gx::DnaNucleobase value_type; static constexpr value_type max() { return value_type::T; } (...) และstd::cout << std::numeric_limits<::gx::DnaNucleobase>::max() << std::endl;พิมพ์ผลลัพธ์ที่คาดหวัง ทดสอบด้วยรสชาติ gcc 5.2.1 และ 4.8 / 4.9
Wojciech Migda

2
-1; ping ฉันถ้าคุณเปลี่ยนคำตอบฉันจะได้ยกเลิกการโหวตได้ คำตอบนี้เป็นแบบแผนที่ไม่ดีที่จะปฏิบัติตาม numeric_limits<T>::max()มันเป็นความผิดของแนวคิดของ สิ่งเดียวที่ฟังก์ชันสามารถคืนค่าได้อย่างสมเหตุสมผลคือค่าที่แจกแจงสูงสุด มันจะกลับมา2แต่ OP (ในกรณีนี้โดยเฉพาะ) 3จะต้องให้มันกลับมา เมื่อคุณมีค่าที่ไม่ใช่ค่าเริ่มต้นสำหรับ enum ( FB = 2057) การเดิมพันทั้งหมดจะถูกปิดไม่สามารถแม้แต่+ 1จะแฮ็คข้อผิดพลาดแบบออฟ - ต่อ หากมีnumeric_limits<T>::number_of_elements_of_the_set()(หรือชื่อที่สั้นกว่า) สามารถใช้ได้โดยไม่มีความคลุมเครือ
Merlyn Morgan-Graham

3

เพิ่มรายการที่ส่วนท้ายของ enum เรียกว่า Folders_MAX หรือสิ่งที่คล้ายกันและใช้ค่านี้เมื่อเริ่มต้นอาร์เรย์ของคุณ

ContainerClass* m_containers[Folders_MAX];

2

ฉันชอบใช้ enums เป็นอาร์กิวเมนต์สำหรับฟังก์ชันของฉัน เป็นวิธีง่ายๆในการระบุรายการ "ตัวเลือก" แบบตายตัว ปัญหาเกี่ยวกับคำตอบที่ได้รับการโหวตสูงสุดที่นี่คือการใช้สิ่งนี้ลูกค้าสามารถระบุ "ตัวเลือกที่ไม่ถูกต้อง" ในการหมุนฉันขอแนะนำให้ทำสิ่งเดียวกันเป็นหลัก แต่ใช้ int คงที่นอก enum เพื่อกำหนดจำนวนของพวกเขา

enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;

ไม่น่าพอใจ แต่เป็นวิธีแก้ปัญหาที่สะอาดหากคุณไม่เปลี่ยน enum โดยไม่ต้องอัปเดตค่าคงที่


1

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

enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }

ในตัวอย่างนี้ผลลัพธ์จะสร้างอาร์เรย์ 3 รายการเมื่อคุณต้องการอาร์เรย์ 5 รายการ

enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }

ในตัวอย่างนี้ผลลัพธ์จะสร้างอาร์เรย์ 301 รายการเมื่อคุณต้องการอาร์เรย์ 5 รายการ

วิธีที่ดีที่สุดในการแก้ปัญหานี้ในกรณีทั่วไปคือการทำซ้ำผ่านการแจงนับของคุณ แต่นั่นยังไม่อยู่ในมาตรฐานเท่าที่ฉันรู้

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