C ++: พิมพ์ค่า enum เป็นข้อความ


91

ถ้าฉันมี enum แบบนี้

enum Errors
{ErrorA=0, ErrorB, ErrorC};

จากนั้นฉันต้องการพิมพ์ลงในคอนโซล

Errors anError = ErrorA;
cout<<anError;/// 0 will be printed

แต่สิ่งที่ฉันต้องการคือข้อความ "ErrorA" ฉันสามารถทำได้โดยไม่ใช้ if / switch หรือไม่?
แล้วทางออกของคุณสำหรับเรื่องนี้คืออะไร?


ฉันคิดว่าคำตอบของฉันค่อนข้างดีคุณช่วยดูไหม
เสี่ยว


คำตอบ:


64

การใช้แผนที่:

#include <iostream>
#include <map>
#include <string>

enum Errors {ErrorA=0, ErrorB, ErrorC};

std::ostream& operator<<(std::ostream& out, const Errors value){
    static std::map<Errors, std::string> strings;
    if (strings.size() == 0){
#define INSERT_ELEMENT(p) strings[p] = #p
        INSERT_ELEMENT(ErrorA);     
        INSERT_ELEMENT(ErrorB);     
        INSERT_ELEMENT(ErrorC);             
#undef INSERT_ELEMENT
    }   

    return out << strings[value];
}

int main(int argc, char** argv){
    std::cout << ErrorA << std::endl << ErrorB << std::endl << ErrorC << std::endl;
    return 0;   
}

การใช้โครงสร้างอาร์เรย์ด้วยการค้นหาเชิงเส้น:

#include <iostream>
#include <string>

enum Errors {ErrorA=0, ErrorB, ErrorC};

std::ostream& operator<<(std::ostream& out, const Errors value){
#define MAPENTRY(p) {p, #p}
    const struct MapEntry{
        Errors value;
        const char* str;
    } entries[] = {
        MAPENTRY(ErrorA),
        MAPENTRY(ErrorB),
        MAPENTRY(ErrorC),
        {ErrorA, 0}//doesn't matter what is used instead of ErrorA here...
    };
#undef MAPENTRY
    const char* s = 0;
    for (const MapEntry* i = entries; i->str; i++){
        if (i->value == value){
            s = i->str;
            break;
        }
    }

    return out << s;
}

int main(int argc, char** argv){
    std::cout << ErrorA << std::endl << ErrorB << std::endl << ErrorC << std::endl;
    return 0;   
}

การใช้สวิตช์ / เคส:

#include <iostream>
#include <string>

enum Errors {ErrorA=0, ErrorB, ErrorC};

std::ostream& operator<<(std::ostream& out, const Errors value){
    const char* s = 0;
#define PROCESS_VAL(p) case(p): s = #p; break;
    switch(value){
        PROCESS_VAL(ErrorA);     
        PROCESS_VAL(ErrorB);     
        PROCESS_VAL(ErrorC);
    }
#undef PROCESS_VAL

    return out << s;
}

int main(int argc, char** argv){
    std::cout << ErrorA << std::endl << ErrorB << std::endl << ErrorC << std::endl;
    return 0;   
}

12
-1. เพียงแค่เปลี่ยนเคสแทนการใช้แฮชแมป ความซับซ้อนที่เพิ่มขึ้นไม่ใช่เรื่องดี
Simon

8
จุดดี. ครั้งต่อไปฉันจะ :) แต่ตอนนี้ฉันเห็นว่าคุณได้แก้ไขโพสต์ของคุณแล้วเพื่อเพิ่มฟังก์ชันการทำงานที่ฉันกำลังมองหา เก่งมาก!
Simon

1
#p คืออะไร? ถ้าในตัวอย่างที่สามแทนที่จะใช้ enum ฉันใช้คลาส enum เป็นไปได้ไหมที่จะรับเฉพาะสตริง enum ที่ไม่มีชื่อคลาส
rh0x

2
#pคือตัวประมวลผลก่อนกำหนดสตริง p ดังนั้นการโทรPROCESS_VAL(ErrorA)จะส่งออก: case(ErrorA): s = "ErrorA"; break;.
Nashenas

ผมไม่คิดว่ามันจะเป็นทางออกที่ดีที่สุด: เหตุผล: 1) มีการรักษาสองครั้งenumค่าซึ่งผมคิดว่าเป็นNO-GO 2) เมื่อฉันเข้าใจวิธีแก้ปัญหาอย่างถูกต้องมันใช้ได้กับหนึ่งenumเท่านั้น
Peter VARGA

30

ใช้อาร์เรย์หรือเวกเตอร์ของสตริงที่มีค่าที่ตรงกัน:

char *ErrorTypes[] =
{
    "errorA",
    "errorB",
    "errorC"
};

cout << ErrorTypes[anError];

แก้ไข: วิธีแก้ปัญหาข้างต้นใช้ได้เมื่อ enum ติดกันกล่าวคือเริ่มจาก 0 และไม่มีค่าที่กำหนด มันจะทำงานได้ดีกับ enum ในคำถาม

หากต้องการพิสูจน์เพิ่มเติมสำหรับกรณีที่ enum ไม่ได้เริ่มจาก 0 ให้ใช้:

cout << ErrorTypes[anError - ErrorA];

4
น่าเสียดายที่ enum ช่วยให้เราสามารถกำหนดค่าให้กับองค์ประกอบได้ คุณจะทำงานอย่างไรหากคุณมี enums ที่ไม่ใช่ contiguos บรรทัด 'enum Status {OK = 0, Fail = -1, OutOfMemory = -2, IOError = -1000, ConversionError = -2000} `(ดังนั้นคุณสามารถเพิ่ม IOErrors ในภายหลังได้ ถึงช่วง -1001-1999)
Nordic Mainframe

@Luther: ใช่นี้จะทำงานเฉพาะกับ enums ต่อเนื่องกันซึ่ง enums มากที่สุดคือ ในกรณีที่ enum ไม่ติดกันคุณจะต้องใช้แนวทางอื่นเช่นแผนที่ แต่ในกรณีที่มีปัญหาต่อเนื่องกันฉันขอแนะนำให้ใช้แนวทางนี้และอย่าให้ซับซ้อนมากเกินไป
Igor Oks

2
ดังนั้นหากเพื่อนร่วมงานของฉันเพิ่ม NewValue ให้กับ enum และไม่อัปเดตอาร์เรย์ ErrorTypes ErrorTypes [NewValue] จะให้อะไร และฉันจะจัดการกับค่า enum เชิงลบได้อย่างไร?
Nordic Mainframe

2
@ Luther: คุณจะต้องอัปเดต ErrorTypes อยู่เสมอ อีกครั้งมีการแลกเปลี่ยนระหว่างความเรียบง่ายและความเป็นสากลขึ้นอยู่กับสิ่งที่สำคัญกว่าสำหรับผู้ใช้ ปัญหาเกี่ยวกับค่า enum เชิงลบคืออะไร?
Igor Oks

1
อาร์เรย์นี้ไม่ควรคงที่เพื่อประสิทธิภาพของหน่วยความจำใช่หรือไม่? และ const เพื่อความปลอดภัย?
Jonathan

15

นี่คือตัวอย่างจาก Boost.Preprocessor:

#include <iostream>

#include <boost/preprocessor/punctuation/comma.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>


#define DEFINE_ENUM(name, values)                               \
  enum name {                                                   \
    BOOST_PP_SEQ_FOR_EACH(DEFINE_ENUM_VALUE, , values)          \
  };                                                            \
  inline const char* format_##name(name val) {                  \
    switch (val) {                                              \
      BOOST_PP_SEQ_FOR_EACH(DEFINE_ENUM_FORMAT, , values)       \
    default:                                                    \
        return 0;                                               \
    }                                                           \
  }

#define DEFINE_ENUM_VALUE(r, data, elem)                        \
  BOOST_PP_SEQ_HEAD(elem)                                       \
  BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(elem), 2),      \
               = BOOST_PP_SEQ_TAIL(elem), )                     \
  BOOST_PP_COMMA()

#define DEFINE_ENUM_FORMAT(r, data, elem)             \
  case BOOST_PP_SEQ_HEAD(elem):                       \
  return BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(elem));


DEFINE_ENUM(Errors,
            ((ErrorA)(0))
            ((ErrorB))
            ((ErrorC)))

int main() {
  std::cout << format_Errors(ErrorB) << std::endl;
}

2
+1, โซลูชันนี้ไม่ได้อาศัยเครื่องมือภายนอกเช่นคำตอบของ lua ด้านบน แต่เป็น C ++ ที่บริสุทธิ์ซึ่งเป็นไปตามหลักการ DRY และไวยากรณ์ของผู้ใช้สามารถอ่านได้ (หากจัดรูปแบบถูกต้อง BTW คุณไม่จำเป็นต้องใช้แบ็กสแลช เมื่อใช้ DEFINE_ENUM ซึ่งดูเป็นธรรมชาติกว่าเล็กน้อย IMO)
Fabio Fracassi

3
@Fabio Fracassi: "โซลูชันนี้ไม่ต้องพึ่งพาเครื่องมือภายนอก" Boost เป็นเครื่องมือภายนอก - ไลบรารี C ++ ที่ไม่ได้มาตรฐาน นอกจากนี้มันค่อนข้างยาวเกินไป การแก้ไขปัญหาควรง่ายที่สุด อันนี้ไม่เข้าข่าย ...
SigTerm

2
จริงๆแล้วมันคือทั้งหมดที่คุณสามารถใส่โค้ดส่วนใหญ่ได้ (อันที่จริงทั้งหมดนี้ยกเว้นนิยามจริง) สามารถใส่ลงในส่วนหัวเดียว นี่จึงเป็นคำตอบที่สั้นที่สุดที่นำเสนอที่นี่ และสำหรับการเพิ่มเป็นภายนอกใช่ แต่น้อยกว่าสคริปต์ที่ไม่อยู่ในภาษาสำหรับการประมวลผลส่วนล่วงหน้าของซอร์สตามที่สคริปต์ lua ด้านบนเป็น นอกจากบูสต์จะใกล้เคียงกับมาตรฐานที่ควรมีในกล่องเครื่องมือโปรแกรมเมอร์ C ++ ทุกตัว แน่นอน IMHO
Fabio Fracassi

[ฉันได้ลบการขึ้นบรรทัดใหม่ที่ไม่จำเป็นในการเรียกมาโครแล้ว ไม่จำเป็น: การเรียกมาโครสามารถขยายได้หลายบรรทัด]
James McNellis

มาโครDEFINE_ENUMทำให้ฉันมีข้อผิดพลาดmultiple definition of `format_ProgramStatus(ProgramStatus)'เมื่อฉันพยายามใช้งาน
HelloGoodbye

6

คุณสามารถใช้เคล็ดลับตัวประมวลผลล่วงหน้าที่ง่ายกว่านี้ได้หากคุณต้องการแสดงรายการของคุณenumในไฟล์ภายนอก

/* file: errors.def */
/* syntax: ERROR_DEF(name, value) */
ERROR_DEF(ErrorA, 0x1)
ERROR_DEF(ErrorB, 0x2)
ERROR_DEF(ErrorC, 0x4)

จากนั้นในซอร์สไฟล์คุณจะถือว่าไฟล์นั้นเหมือนกับไฟล์รวม แต่คุณกำหนดสิ่งที่คุณต้องการERROR_DEFให้ทำ

enum Errors {
#define ERROR_DEF(x,y) x = y,
#include "errors.def"
#undef ERROR_DEF
};

static inline std::ostream & operator << (std::ostream &o, Errors e) {
    switch (e) {
    #define ERROR_DEF(x,y) case y: return o << #x"[" << y << "]";
    #include "errors.def"
    #undef ERROR_DEF
    default: return o << "unknown[" << e << "]";
    }
}

หากคุณใช้เครื่องมือค้นหาแหล่งที่มา (เช่น cscope) คุณจะต้องแจ้งให้ทราบเกี่ยวกับไฟล์ภายนอก


4

มีการอภิปรายที่นี่ซึ่งอาจช่วยได้: มีวิธีง่ายๆในการแปลง C ++ enum เป็นสตริงหรือไม่?

UPDATE: นี่ # sa script สำหรับ Lua ซึ่งสร้างตัวดำเนินการ << สำหรับแต่ละชื่อ enum ที่พบ สิ่งนี้อาจต้องใช้การทำงานบางอย่างเพื่อให้สามารถใช้งานได้สำหรับกรณีที่เรียบง่ายน้อยกว่า [1]:

function make_enum_printers(s)
    for n,body in string.gmatch(s,'enum%s+([%w_]+)%s*(%b{})') do
    print('ostream& operator<<(ostream &o,'..n..' n) { switch(n){') 
    for k in string.gmatch(body,"([%w_]+)[^,]*") do
    print('  case '..k..': return o<<"'..k..'";')
    end
    print('  default: return o<<"(invalid value)"; }}')
    end
end

local f=io.open(arg[1],"r")
local s=f:read('*a')
make_enum_printers(s)

ให้ข้อมูลนี้:

enum Errors
{ErrorA=0, ErrorB, ErrorC};

enum Sec {
    X=1,Y=X,foo_bar=X+1,Z
};

มันผลิต:

ostream& operator<<(ostream &o,Errors n) { switch(n){
  case ErrorA: return o<<"ErrorA";
  case ErrorB: return o<<"ErrorB";
  case ErrorC: return o<<"ErrorC";
  default: return o<<"(invalid value)"; }}
ostream& operator<<(ostream &o,Sec n) { switch(n){
  case X: return o<<"X";
  case Y: return o<<"Y";
  case foo_bar: return o<<"foo_bar";
  case Z: return o<<"Z";
  default: return o<<"(invalid value)"; }}

นั่นอาจเป็นการเริ่มต้นสำหรับคุณ

[1] enum ในขอบเขตเนมสเปซที่แตกต่างกันหรือไม่ใช่เนมสเปซ enums ที่มีนิพจน์ initializer ซึ่งมีคอมมาเป็นต้น


เป็นธรรมเนียมที่จะแสดงความคิดเห็น '-1' เพื่อให้ผู้โพสต์มีโอกาสแก้ไขคำตอบหรือไม่? แค่ถาม ..
Nordic Mainframe

2
ฉันคิดว่าโซลูชัน Boost PP ด้านล่าง (จาก Philip) ดีกว่าเพราะการใช้เครื่องมือภายนอกนั้นมีค่าใช้จ่ายในการบำรุงรักษาที่ชาญฉลาด แต่ไม่ใช่ -1 เพราะคำตอบนั้นถูกต้อง
Fabio Fracassi

4
Boost PP เป็นปัญหาในการบำรุงรักษาเช่นกันเนื่องจากคุณต้องการให้ทุกคนพูดภาษาโลหะ Boost PP ซึ่งแย่มากง่ายต่อการแตกหัก (มักให้ข้อความแสดงข้อผิดพลาดที่ใช้ไม่ได้) และมีเพียงการใช้งานที่ จำกัด เท่านั้น (lua / python / perl สามารถสร้างรหัสจากโดยพลการ ข้อมูลภายนอก) จะเพิ่มรายการที่ต้องพึ่งพาให้กับคุณซึ่งอาจไม่ได้รับอนุญาตเนื่องจากนโยบายโครงการ นอกจากนี้ยังเป็นการรุกรานเนื่องจากคุณต้องกำหนด enums ของคุณใน DSL เครื่องมือซอร์สโค้ดที่คุณชื่นชอบหรือ IDE อาจมีปัญหากับสิ่งนั้น และสุดท้าย แต่ไม่ท้ายสุด: คุณไม่สามารถกำหนดจุดพักในการขยายได้
Nordic Mainframe

4

ฉันใช้อาร์เรย์สตริงเมื่อใดก็ตามที่ฉันกำหนด enum:

รายละเอียด h

#pragma once

struct Profile
{
    enum Value
    {
        Profile1,
        Profile2,
    };

    struct StringValueImplementation
    {
        const wchar_t* operator[](const Profile::Value profile)
        {
            switch (profile)
            {
            case Profile::Profile1: return L"Profile1";
            case Profile::Profile2: return L"Profile2";
            default: ASSERT(false); return NULL;
            }
        }
    };

    static StringValueImplementation StringValue;
};

Profile.cpp

#include "Profile.h"

Profile::StringValueImplementation Profile::StringValue;

4

นี่เป็นวิธีที่ดี

enum Rank { ACE = 1, DEUCE, TREY, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING };

พิมพ์ด้วยอาร์เรย์ของอักขระ

const char* rank_txt[] = {"Ace", "Deuce", "Trey", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Four", "King" } ;

แบบนี้

std::cout << rank_txt[m_rank - 1]

2
จะเกิดอะไรขึ้นถ้า enum ของฉันเริ่มตั้งแต่ปี 2000? วิธีนี้จะไม่ทำงาน
Sitesh

3
#include <iostream>
using std::cout;
using std::endl;

enum TEnum
{ 
  EOne,
  ETwo,
  EThree,
  ELast
};

#define VAR_NAME_HELPER(name) #name
#define VAR_NAME(x) VAR_NAME_HELPER(x)

#define CHECK_STATE_STR(x) case(x):return VAR_NAME(x);

const char *State2Str(const TEnum state)
{
  switch(state)
  {
    CHECK_STATE_STR(EOne);
    CHECK_STATE_STR(ETwo);
    CHECK_STATE_STR(EThree);
    CHECK_STATE_STR(ELast);
    default:
      return "Invalid";
  }
}

int main()
{
  int myInt=12345;
  cout << VAR_NAME(EOne) " " << VAR_NAME(myInt) << endl;

  for(int i = -1; i < 5;   i)
    cout << i << " " << State2Str((TEnum)i) << endl;
  return 0;
}

2

คุณสามารถใช้คอนเทนเนอร์แผนที่ stl ....

typedef map<Errors, string> ErrorMap;

ErrorMap m;
m.insert(ErrorMap::value_type(ErrorA, "ErrorA"));
m.insert(ErrorMap::value_type(ErrorB, "ErrorB"));
m.insert(ErrorMap::value_type(ErrorC, "ErrorC"));

Errors error = ErrorA;

cout << m[error] << endl;

4
แผนที่นี้ดีกว่าswitch(n) { case XXX: return "XXX"; ... }อย่างไร ซึ่งมีการค้นหา O (1) และไม่จำเป็นต้องเริ่มต้น? หรือ enums เปลี่ยนแปลงอย่างใดในระหว่างรันไทม์?
Nordic Mainframe

ฉันเห็นด้วยกับ @Luther Blissett เกี่ยวกับการใช้คำสั่งสวิตช์ (หรือตัวชี้ฟังก์ชันด้วย)
KedarX

1
เขาอาจต้องการแสดงผล "ลูเธอร์เพื่อนรักของฉันคนนี้คือข้อผิดพลาด A หรือ" เอเดรียนเพื่อนรักของฉันคนนี้คือข้อผิดพลาด B "นอกจากนี้การใช้แผนที่จะลบการพึ่งพาลายเซ็น iostream ซึ่งทำให้เขามีอิสระที่จะใช้ที่อื่นใน โค้ดที่มีการต่อสตริงเช่นสตริง x = "สวัสดี" + m [ErrorA] เป็นต้น
Adrian Regan

ฉันแน่ใจว่า std :: map มี if และสวิตช์จำนวนมาก ฉันจะอ่านว่า 'ฉันจะทำสิ่งนี้ได้อย่างไรโดยไม่ต้องให้ฉันเขียน if และสวิตช์'
Nordic Mainframe

ฉันแน่ใจว่ามันทำได้ แต่ไม่ต้องการให้คุณเขียนสคริปต์ใน Lua เพื่อแก้ปัญหา ...
Adrian Regan

1

สำหรับปัญหานี้ฉันทำหน้าที่ช่วยเหลือดังนี้:

const char* name(Id id) {
    struct Entry {
        Id id;
        const char* name;
    };
    static const Entry entries[] = {
        { ErrorA, "ErrorA" },
        { ErrorB, "ErrorB" },
        { 0, 0 }
    }
    for (int it = 0; it < gui::SiCount; ++it) {
        if (entries[it].id == id) {
            return entries[it].name;
        }
    }
   return 0;
}

การค้นหาเชิงเส้นมักจะมีประสิทธิภาพมากกว่าstd::mapสำหรับคอลเล็กชันขนาดเล็กเช่นนี้


1

โซลูชันนี้ไม่ต้องการให้คุณใช้โครงสร้างข้อมูลหรือสร้างไฟล์อื่น

โดยทั่วไปคุณกำหนดค่า enum ทั้งหมดของคุณใน #define จากนั้นใช้ในตัวดำเนินการ << คล้ายกับคำตอบของ @ jxh มาก

ลิงค์ ideone สำหรับการทำซ้ำขั้นสุดท้าย: http://ideone.com/hQTKQp

รหัสเต็ม:

#include <iostream>

#define ERROR_VALUES ERROR_VALUE(NO_ERROR)\
ERROR_VALUE(FILE_NOT_FOUND)\
ERROR_VALUE(LABEL_UNINITIALISED)

enum class Error
{
#define ERROR_VALUE(NAME) NAME,
    ERROR_VALUES
#undef ERROR_VALUE
};

inline std::ostream& operator<<(std::ostream& os, Error err)
{
    int errVal = static_cast<int>(err);
    switch (err)
    {
#define ERROR_VALUE(NAME) case Error::NAME: return os << "[" << errVal << "]" #NAME;
    ERROR_VALUES
#undef ERROR_VALUE
    default:
        // If the error value isn't found (shouldn't happen)
        return os << errVal;
    }
}

int main() {
    std::cout << "Error: " << Error::NO_ERROR << std::endl;
    std::cout << "Error: " << Error::FILE_NOT_FOUND << std::endl;
    std::cout << "Error: " << Error::LABEL_UNINITIALISED << std::endl;
    return 0;
}

เอาท์พุต:

Error: [0]NO_ERROR
Error: [1]FILE_NOT_FOUND
Error: [2]LABEL_UNINITIALISED

สิ่งที่ดีในการทำเช่นนี้คือคุณสามารถระบุข้อความที่คุณกำหนดเองสำหรับแต่ละข้อผิดพลาดได้หากคุณคิดว่าคุณต้องการ:

#include <iostream>

#define ERROR_VALUES ERROR_VALUE(NO_ERROR, "Everything is fine")\
ERROR_VALUE(FILE_NOT_FOUND, "File is not found")\
ERROR_VALUE(LABEL_UNINITIALISED, "A component tried to the label before it was initialised")

enum class Error
{
#define ERROR_VALUE(NAME,DESCR) NAME,
    ERROR_VALUES
#undef ERROR_VALUE
};

inline std::ostream& operator<<(std::ostream& os, Error err)
{
    int errVal = static_cast<int>(err);
    switch (err)
    {
#define ERROR_VALUE(NAME,DESCR) case Error::NAME: return os << "[" << errVal << "]" #NAME <<"; " << DESCR;
    ERROR_VALUES
#undef ERROR_VALUE
    default:
        return os << errVal;
    }
}

int main() {
    std::cout << "Error: " << Error::NO_ERROR << std::endl;
    std::cout << "Error: " << Error::FILE_NOT_FOUND << std::endl;
    std::cout << "Error: " << Error::LABEL_UNINITIALISED << std::endl;
    return 0;
}

เอาท์พุต:

Error: [0]NO_ERROR; Everything is fine
Error: [1]FILE_NOT_FOUND; File is not found
Error: [2]LABEL_UNINITIALISED; A component tried to the label before it was initialised

หากคุณชอบสร้างรหัสข้อผิดพลาด / คำอธิบายที่สื่อความหมายมากคุณอาจไม่ต้องการให้รหัสเหล่านี้อยู่ในรุ่นที่ใช้งานจริง การปิดใช้งานเพื่อให้พิมพ์เฉพาะค่าได้ง่าย:

inline std::ostream& operator<<(std::ostream& os, Error err)
{
    int errVal = static_cast<int>(err);
    switch (err)
    {
    #ifndef PRODUCTION_BUILD // Don't print out names in production builds
    #define ERROR_VALUE(NAME,DESCR) case Error::NAME: return os << "[" << errVal << "]" #NAME <<"; " << DESCR;
        ERROR_VALUES
    #undef ERROR_VALUE
    #endif
    default:
        return os << errVal;
    }
}

เอาท์พุต:

Error: 0
Error: 1
Error: 2

หากเป็นกรณีนี้การค้นหาข้อผิดพลาดหมายเลข 525 จะเป็น PITA เราสามารถระบุตัวเลขใน enum เริ่มต้นได้ด้วยตนเองดังนี้:

#define ERROR_VALUES ERROR_VALUE(NO_ERROR, 0, "Everything is fine")\
ERROR_VALUE(FILE_NOT_FOUND, 1, "File is not found")\
ERROR_VALUE(LABEL_UNINITIALISED, 2, "A component tried to the label before it was initialised")\
ERROR_VALUE(UKNOWN_ERROR, -1, "Uh oh")

enum class Error
{
#define ERROR_VALUE(NAME,VALUE,DESCR) NAME=VALUE,
    ERROR_VALUES
#undef ERROR_VALUE
};

inline std::ostream& operator<<(std::ostream& os, Error err)
{
    int errVal = static_cast<int>(err);
    switch (err)
    {
#ifndef PRODUCTION_BUILD // Don't print out names in production builds
#define ERROR_VALUE(NAME,VALUE,DESCR) case Error::NAME: return os << "[" #VALUE  "]" #NAME <<"; " << DESCR;
    ERROR_VALUES
#undef ERROR_VALUE
#endif
    default:
        return os <<errVal;
    }
}
    ERROR_VALUES
#undef ERROR_VALUE
#endif
    default:
    {
        // If the error value isn't found (shouldn't happen)
        return os << static_cast<int>(err);
        break;
    }
    }
}

เอาท์พุต:

Error: [0]NO_ERROR; Everything is fine
Error: [1]FILE_NOT_FOUND; File is not found
Error: [2]LABEL_UNINITIALISED; A component tried to the label before it was initialised
Error: [-1]UKNOWN_ERROR; Uh oh

0

แล้วเรื่องนี้ล่ะ?

    enum class ErrorCodes : int{
          InvalidInput = 0
    };

    std::cout << ((int)error == 0 ? "InvalidInput" : "") << std::endl;

ฯลฯ ... ฉันรู้ว่านี่เป็นตัวอย่างที่ได้รับการออกแบบมาอย่างดี แต่ฉันคิดว่ามันมีแอพพลิเคชั่นที่ใช้ได้และจำเป็นและสั้นกว่าการเขียนสคริปต์อย่างแน่นอน


0

ใช้พรีโปรเซสเซอร์:

#define VISIT_ERROR(FIRST, MIDDLE, LAST) \
    FIRST(ErrorA) MIDDLE(ErrorB) /* MIDDLE(ErrorB2) */ LAST(ErrorC)

enum Errors
{
    #define ENUMFIRST_ERROR(E)  E=0,
    #define ENUMMIDDLE_ERROR(E) E,
    #define ENUMLAST_ERROR(E)   E
    VISIT_ERROR(ENUMFIRST_ERROR, ENUMMIDDLE_ERROR, ENUMLAST_ERROR)
    // you might undefine the 3 macros defined above
};

std::string toString(Error e)
{
    switch(e)
    {
    #define CASERETURN_ERROR(E)  case E: return #E;
    VISIT_ERROR(CASERETURN_ERROR, CASERETURN_ERROR, CASERETURN_ERROR)
    // you might undefine the above macro.
    // note that this will produce compile-time error for synonyms in enum;
    // handle those, if you have any, in a distinct macro

    default:
        throw my_favourite_exception();
    }
}

ข้อดีของแนวทางนี้คือ - ยังเข้าใจง่าย แต่ยังช่วยให้สามารถเยี่ยมชมได้หลากหลาย (ไม่ใช่แค่สตริง)

หากคุณยินดีที่จะทิ้งสิ่งแรกให้สร้างมาโคร FOREACH () ด้วยตัวคุณเองจากนั้น#define ERROR_VALUES() (ErrorA, ErrorB, ErrorC)เขียนผู้เยี่ยมชมของคุณในรูปแบบของ FOREACH () จากนั้นลองตรวจสอบโค้ด :)


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