C ++: In ra giá trị enum dưới dạng văn bản


88

Nếu tôi có một enum như thế này

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

Sau đó, tôi muốn in ra bảng điều khiển

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

nhưng những gì tôi muốn là văn bản "ErrorA", tôi có thể làm điều đó mà không sử dụng if / switch không?
Và giải pháp của bạn cho điều này là gì?


Tôi nghĩ câu trả lời của tôi khá hay, bạn có phiền xem qua không?
Xiao,


Câu trả lời:


63

Sử dụng bản đồ:

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

Sử dụng mảng cấu trúc với tìm kiếm tuyến tính:

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

Sử dụng công tắc / trường hợp:

#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. Chỉ cần thực hiện switch-case thay vì sử dụng hash-map. Tăng độ phức tạp không phải là một điều tốt.
Simon,

8
Điểm tốt. Lần sau tôi sẽ làm :) Nhưng bây giờ tôi thấy rằng bạn đã chỉnh sửa bài đăng của mình để thêm loại chức năng tôi đang tìm kiếm. Làm tốt lắm!
Simon

1
#p là gì? Nếu trong ví dụ thứ ba thay vì enum, tôi sử dụng một lớp enum, thì có thể chỉ lấy chuỗi enum mà không có tên lớp không?
rh0x

2
#plà bộ tiền xử lý xâu chuỗi p. Vì vậy, kêu gọi PROCESS_VAL(ErrorA)ý chí đầu ra: case(ErrorA): s = "ErrorA"; break;.
Nashenas

Tôi không coi đó là giải pháp tối ưu: Lý do: 1) Tôi phải duy trì gấp đôi các enumgiá trị mà tôi nghĩ là KHÔNG ĐƯỢC . 2) Khi tôi hiểu giải pháp một cách chính xác, nó chỉ hoạt động cho một enum.
Peter VARGA

28

Sử dụng một mảng hoặc vectơ chuỗi có các giá trị phù hợp:

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

cout << ErrorTypes[anError];

CHỈNH SỬA: Giải pháp trên có thể áp dụng khi enum liền kề, tức là bắt đầu từ 0 và không có giá trị được gán. Nó sẽ hoạt động hoàn hảo với enum trong câu hỏi.

Để chứng minh thêm cho trường hợp enum không bắt đầu từ 0, hãy sử dụng:

cout << ErrorTypes[anError - ErrorA];

4
thật không may, enum cho phép chúng ta gán giá trị cho các phần tử. Phương pháp tiếp cận của bạn hoạt động như thế nào nếu bạn có các enum không phải contiguos, dòng 'enum Status {OK = 0, Fail = -1, OutOfMemory = -2, IOError = -1000, ConversionError = -2000}' (để sau này bạn có thể thêm IOErrors đến phạm vi -1001-1999)
Nordic Mainframe

@Luther: Có, điều này sẽ chỉ hoạt động với các ô liền kề, mà hầu hết các ô đều như vậy . Trong trường hợp enum đó không liền nhau, bạn sẽ cần sử dụng một cách tiếp cận khác, tức là bản đồ. Nhưng trong trường hợp bao quanh liền kề, tôi khuyên bạn nên sử dụng cách tiếp cận này, và không quá phức tạp.
Igor Oks

2
Vì vậy, nếu đồng nghiệp của tôi thêm NewValue vào một enum và không cập nhật mảng ErrorTypes, thì ErrorTypes [NewValue] mang lại kết quả gì? Và làm cách nào để xử lý các giá trị enum âm?
Nordic Mainframe

2
@Luther: Bạn sẽ phải cập nhật ErrorTypes. Một lần nữa, có sự cân bằng giữa tính đơn giản và tính phổ biến, phụ thuộc vào điều gì quan trọng hơn đối với người dùng. Vấn đề với các giá trị enum âm là gì?
Igor Oks

1
Mảng này không nên tĩnh để tăng hiệu quả bộ nhớ? và const để an toàn?
Jonathan

15

Đây là một ví dụ dựa trên 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, Giải pháp này không dựa vào công cụ bên ngoài, như câu trả lời lua ở trên, mà là C ++ thuần túy, nó tuân theo nguyên tắc DRY và cú pháp người dùng có thể đọc được (nếu định dạng đúng. BTW, bạn không cần Dấu gạch chéo ngược khi sử dụng DEFINE_ENUM, trông tự nhiên hơn một chút, IMO)
Fabio Fracassi

3
@Fabio Fracassi: "Giải pháp này không dựa vào công cụ bên ngoài" Boost là một công cụ bên ngoài - thư viện C ++ không chuẩn. Với lại, nó hơi dài. Giải pháp cho một vấn đề nên càng đơn giản càng tốt. Cái này không đủ điều kiện ...
SIGTERM

2
Trên thực tế, đó là tất cả những gì bạn có thể đặt hầu hết mã (thực tế là tất cả mã ngoại trừ định nghĩa thực tế) đều có thể được đưa vào một tiêu đề duy nhất. vì vậy đây thực sự là giải pháp ngắn nhất được trình bày ở đây. Và để tăng cường là bên ngoài, có, nhưng ít hơn một tập lệnh ngoại ngữ để xử lý trước các phần của nguồn như tập lệnh lua ở trên. Bên cạnh đó, boost gần với tiêu chuẩn đến mức nó phải có trong mọi hộp công cụ của lập trình viên C ++. Tất nhiên chỉ cần IMHO
Fabio Fracassi, 27/07/10

[Tôi đã loại bỏ việc thoát dòng mới không cần thiết trong lệnh gọi macro. Chúng không cần thiết: một lệnh gọi macro có thể kéo dài nhiều dòng.]
James McNellis

Macro DEFINE_ENUMcho tôi lỗi multiple definition of `format_ProgramStatus(ProgramStatus)'khi tôi cố gắng sử dụng nó.
HelloGoodbye

6

Bạn có thể sử dụng một thủ thuật xử lý trước đơn giản hơn nếu bạn sẵn sàng liệt kê các enummục nhập của mình trong một tệp bên ngoài.

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

Sau đó, trong một tệp nguồn, bạn coi tệp đó giống như một tệp bao gồm, nhưng bạn xác định những gì bạn muốn ERROR_DEFlàm.

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

Nếu bạn sử dụng một số công cụ duyệt mã nguồn (như cscope), bạn sẽ phải cho nó biết về tệp bên ngoài.


4

Đã có một cuộc thảo luận ở đây có thể hữu ích: Có cách nào đơn giản để chuyển đổi C ++ enum thành chuỗi không?

CẬP NHẬT: Đây # sa script cho Lua tạo một toán tử << cho mỗi enum có tên mà nó gặp phải. Điều này có thể cần một số công việc để làm cho nó hoạt động trong các trường hợp ít đơn giản hơn [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)

Với đầu vào này:

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

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

Nó tạo ra:

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

Vì vậy, đó có lẽ là một khởi đầu cho bạn.

[1] enums trong các phạm vi khác nhau hoặc không phải không gian tên, enums với các biểu thức khởi tạo chứa komma, v.v.


Ở đây không phải là thông lệ khi nhận xét '-1' để người đăng có cơ hội sửa câu trả lời của họ sao? Chỉ cần hỏi ..
Nordic Mainframe,

2
Tôi nghĩ rằng giải pháp Boost PP dưới đây (của Philip) là tốt hơn, bởi vì sử dụng các công cụ bên ngoài là rất tốn kém để bảo trì khôn ngoan. nhưng không có -1 vì câu trả lời là nếu không hợp lệ
Fabio Fracassi

4
Boost PP cũng là một vấn đề bảo trì, bởi vì bạn cần mọi người nói ngôn ngữ metal của Boost PP, rất khủng khiếp , dễ bị hỏng (đưa ra các thông báo lỗi thường không sử dụng được) và chỉ có khả năng sử dụng hạn chế (lua / python / perl có thể tạo mã từ tùy ý dữ liệu bên ngoài). Nó thêm vào danh sách phụ thuộc của bạn, thậm chí có thể không được phép do chính sách dự án. Ngoài ra, nó là xâm lấn vì nó yêu cầu bạn xác định enums của bạn trong DSL. Công cụ mã nguồn yêu thích của bạn hoặc IDE có thể gặp sự cố với điều đó. Và cuối cùng nhưng không kém phần quan trọng: bạn không thể đặt điểm ngắt trong bản mở rộng.
Nordic Mainframe,

4

Tôi sử dụng một mảng chuỗi bất cứ khi nào tôi xác định một enum:

Hồ sơ.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

Đây là một cách tốt,

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

In nó với một mảng các mảng ký tự

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

Như thế này

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

2
Điều gì sẽ xảy ra nếu enum của tôi bắt đầu từ năm 2000? Giải pháp này sẽ không hoạt động.
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

Bạn có thể sử dụng một vùng chứa bản đồ 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
Làm thế nào đây là một bản đồ tốt hơn switch(n) { case XXX: return "XXX"; ... }? Cái nào có O (1) tra cứu và không cần khởi tạo? Hay enums thay đổi bằng cách nào đó trong thời gian chạy?
Nordic Mainframe

Tôi đồng ý với @Luther Blissett về việc sử dụng câu lệnh switch (hoặc một con trỏ hàm quá)
KedarX

1
Vâng, anh ấy có thể muốn xuất ra "Đây là người bạn thân yêu của tôi, Luther là Lỗi A hoặc" Người bạn thân yêu của tôi, Adrian là Lỗi B. mã với chuỗi nối ví dụ, chuỗi x = "Hello" + m [ErrorA], vv
Adrian Regan

Tôi chắc chắn rằng std :: map chứa rất nhiều if và switch. Tôi sẽ đọc là 'làm thế nào tôi có thể làm điều này mà không có tôi bằng văn bản nếu và công tắc'
Bắc Âu Mainframe

Tôi chắc chắn rằng nó không, nhưng chắc chắn nó không yêu cầu bạn phải viết một kịch bản trong Lua để giải quyết vấn đề ...
Adrian Regan

1

Đối với vấn đề này, tôi thực hiện một chức năng trợ giúp như sau:

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

Tìm kiếm tuyến tính thường hiệu quả hơn so std::mapvới các bộ sưu tập nhỏ như thế này.


1

Giải pháp này không yêu cầu bạn sử dụng bất kỳ cấu trúc dữ liệu nào hoặc tạo một tệp khác.

Về cơ bản, bạn xác định tất cả các giá trị enum của mình trong #define, sau đó sử dụng chúng trong toán tử <<. Rất giống với câu trả lời của @ jxh.

liên kết Ideone cho lần lặp cuối cùng: http://ideone.com/hQTKQp

Mã đầy đủ:

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

Đầu ra:

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

Một điều thú vị khi làm theo cách này là bạn cũng có thể chỉ định các thông báo tùy chỉnh của riêng mình cho từng lỗi nếu bạn cho rằng mình cần chúng:

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

Đầu ra:

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

Nếu bạn muốn làm cho mã lỗi / mô tả của mình thật mô tả, bạn có thể không muốn chúng trong các bản dựng sản xuất. Việc tắt chúng để chỉ in giá trị thật dễ dàng:

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

Đầu ra:

Error: 0
Error: 1
Error: 2

Nếu đúng như vậy, việc tìm lỗi số 525 sẽ là PITA. Chúng ta có thể chỉ định thủ công các số trong enum ban đầu như sau:

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

Đầu ra:

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

Còn cái này thì sao?

    enum class ErrorCodes : int{
          InvalidInput = 0
    };

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

vv ... Tôi biết đây là một ví dụ phức tạp nhưng tôi nghĩ rằng nó có ứng dụng ở những nơi có thể áp dụng và cần thiết và chắc chắn là ngắn hơn so với việc viết kịch bản cho nó.


0

Sử dụng bộ tiền xử lý:

#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();
    }
}

Ưu điểm của cách tiếp cận này là: - nó vẫn còn đơn giản để hiểu - nó cho phép các lượt truy cập khác nhau (không chỉ chuỗi)

Nếu bạn sẵn sàng bỏ lần đầu tiên, hãy tạo cho mình một macro FOREACH (), sau đó #define ERROR_VALUES() (ErrorA, ErrorB, ErrorC)viết khách truy cập của bạn theo nghĩa FOREACH (). Sau đó, cố gắng vượt qua một cuộc đánh giá mã :).


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.