C ++: Cetak nilai enum sebagai teks

91

Jika saya memiliki enum seperti ini

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

Kemudian saya ingin mencetak ke konsol

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

tetapi yang saya inginkan adalah teks "ErrorA", dapatkah saya melakukannya tanpa menggunakan if / switch?
Dan apa solusi Anda untuk ini?

tiboo
sumber
Saya pikir jawaban saya cukup bagus, maukah Anda melihatnya?
Xiao
2
Untuk C ++ 11 enum class: stackoverflow.com/questions/11421432/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
Enum menjadi string: stackoverflow.com/questions/201593/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

64

Menggunakan peta:

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

Menggunakan array struktur dengan pencarian linier:

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

Menggunakan switch / case:

#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;   
}
SigTerm
sumber
12
-1. Lakukan saja switch-case alih-alih menggunakan hash-map. Kompleksitas yang meningkat bukanlah hal yang baik.
Simon
8
Poin yang bagus. Lain kali saya akan :) Tetapi sekarang saya melihat bahwa Anda telah mengedit posting Anda untuk menambahkan jenis fungsionalitas yang saya cari. Kerja bagus!
Simon
1
apa itu #p? jika dalam contoh ketiga, bukan enum, saya menggunakan kelas enum, apakah mungkin hanya mendapatkan string enum tanpa nama kelas?
rh0x
2
#padalah p merangkai preprocessor. Jadi menelepon PROCESS_VAL(ErrorA)akan menampilkan: case(ErrorA): s = "ErrorA"; break;.
Nashenas
Saya tidak menganggap itu sebagai solusi optimal: Alasan: 1) Saya harus menjaga dua kali dengan enumnilai-nilai yang saya pikir adalah NO-GO . 2) Ketika saya memahami solusinya dengan benar, ini hanya berfungsi untuk satu enum.
Peter VARGA
30

Gunakan larik atau vektor string dengan nilai yang cocok:

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

cout << ErrorTypes[anError];

EDIT: Solusi di atas dapat diterapkan ketika enum berdekatan, yaitu dimulai dari 0 dan tidak ada nilai yang ditetapkan. Ini akan bekerja sempurna dengan enum dalam pertanyaan.

Untuk membuktikan lebih lanjut bahwa enum tidak dimulai dari 0, gunakan:

cout << ErrorTypes[anError - ErrorA];
Igor Oks
sumber
4
sayangnya, enum memungkinkan kita untuk menetapkan nilai ke elemen. Bagaimana pendekatan Anda bekerja jika Anda memiliki enum non-contiguos, baris 'enum Status {OK = 0, Fail = -1, OutOfMemory = -2, IOError = -1000, ConversionError = -2000} `(sehingga Anda nanti dapat menambahkan IOErrors hingga kisaran -1001-1999)
Nordic Mainframe
@Luther: Ya, ini hanya akan berfungsi dengan enum yang bersebelahan, yang kebanyakan enum adalah . Jika enum tidak bersebelahan, Anda perlu menggunakan pendekatan lain, yaitu peta. Tapi dalam kasus enum yang berdekatan, saya sarankan untuk menggunakan pendekatan ini, dan tidak terlalu rumit.
Igor Oks
2
Jadi, Jika kolega saya menambahkan NewValue ke enum dan tidak memperbarui array ErrorTypes, maka ErrorTypes [NewValue] menghasilkan apa? Dan bagaimana cara menangani nilai enum negatif?
Nordic Mainframe
2
@Luther: Anda harus terus memperbarui ErrorTypes. Sekali lagi, ada tradeoff antara kesederhanaan dan universalitas, tergantung apa yang lebih penting bagi pengguna. Apa masalah dengan nilai enum negatif?
Igor Oks
1
Bukankah array ini harus statis untuk efisiensi memori? dan const untuk keamanan?
Jonathan
15

Berikut adalah contoh berdasarkan 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;
}
Philipp
sumber
2
+1, Solusi ini tidak bergantung pada alat eksternal, seperti jawaban lua di atas, tetapi murni C ++, mengikuti prinsip KERING, dan sintaks pengguna dapat dibaca (jika diformat dengan benar. BTW, Anda tidak memerlukan Garis miring terbalik saat menggunakan DEFINE_ENUM, yang terlihat sedikit lebih alami, IMO)
Fabio Fracassi
3
@Fabio Fracassi: "Solusi ini tidak bergantung pada alat eksternal" Boost adalah alat eksternal - pustaka C ++ non standar. Lagipula, ini terlalu panjang. Solusi untuk suatu masalah harus sesederhana mungkin. Yang ini tidak memenuhi syarat ...
SigTerm
2
Sebenarnya itu semua Anda bisa meletakkan sebagian besar kode (sebenarnya semua itu kecuali definisi sebenarnya) dapat dimasukkan ke dalam satu header. jadi ini adalah solusi terpendek yang disajikan di sini. Dan untuk meningkatkan menjadi eksternal, ya, tetapi kurang dari skrip keluar bahasa untuk preprocessing bagian dari sumber seperti skrip lua di atas. Selain itu, dorongan sangat dekat dengan standar yang seharusnya ada di setiap kotak alat programmer C ++. Hanya IMHO, tentu saja
Fabio Fracassi
[Saya telah menghapus pelarian baris baru yang tidak diperlukan di pemanggilan makro. Mereka tidak diperlukan: pemanggilan makro dapat menjangkau beberapa baris.]
James McNellis
Makro DEFINE_ENUMmemberi saya kesalahan multiple definition of `format_ProgramStatus(ProgramStatus)'saat saya mencoba menggunakannya.
HelloGoodbye
6

Anda dapat menggunakan trik praproses yang lebih sederhana jika Anda ingin mencantumkan enumentri Anda dalam file eksternal.

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

Kemudian di file sumber, Anda memperlakukan file seperti file sertakan, tetapi Anda menentukan apa yang Anda ingin ERROR_DEFlakukan.

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

Jika Anda menggunakan beberapa alat penelusuran sumber (seperti cscope), Anda harus memberi tahu tentang file eksternal tersebut.

jxh
sumber
4

Telah ada diskusi di sini yang mungkin membantu: Apakah ada cara sederhana untuk mengubah C ++ enum menjadi string?

UPDATE: Berikut ini # skrip untuk Lua yang membuat operator << untuk setiap enum bernama yang ditemuinya. Ini mungkin memerlukan beberapa upaya untuk membuatnya berfungsi pada kasus yang tidak sesederhana itu [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)

Diberikan masukan ini:

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

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

Itu menghasilkan:

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

Jadi itu mungkin awal untuk Anda.

[1] enum dalam cakupan berbeda atau non-namespace, enum dengan ekspresi penginisialisasi yang berisi komma, dll.

Mainframe Nordik
sumber
Bukankah kebiasaan di sini untuk mengomentari '-1' untuk memberi poster kesempatan untuk memperbaiki jawaban mereka? Hanya bertanya ..
Nordic Mainframe
2
Saya pikir solusi Boost PP di bawah (dari Philip) lebih baik, karena menggunakan alat eksternal sangat mahal perawatannya. tetapi tidak -1 karena jawabannya selain valid
Fabio Fracassi
4
Boost PP juga merupakan masalah pemeliharaan, karena Anda membutuhkan semua orang untuk menggunakan bahasa metal Boost PP, yang mengerikan , mudah rusak (biasanya memberikan pesan kesalahan yang tidak dapat digunakan) dan hanya kegunaan terbatas (lua / python / perl dapat menghasilkan kode dari sembarang) data eksternal). Ini menambah dorongan ke daftar ketergantungan Anda, yang bahkan mungkin tidak diizinkan karena kebijakan proyek. Juga, ini invasif karena mengharuskan Anda untuk menentukan enum Anda di DSL. Alat kode sumber atau IDE favorit Anda mungkin bermasalah dengan itu. Dan yang tak kalah pentingnya: Anda tidak dapat menetapkan breakpoint dalam ekspansi.
Nordic Mainframe
4

Saya menggunakan array string setiap kali saya mendefinisikan enum:

Profile.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;
Tandai Ingram
sumber
4

Ini cara yang bagus,

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

Cetak dengan array array karakter

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

Seperti ini

std::cout << rank_txt[m_rank - 1]
MrPickles7
sumber
2
Bagaimana jika enum saya dimulai dari tahun 2000? Solusi ini tidak akan berhasil.
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;
}
Vladimir Chernyshev
sumber
2

Anda bisa menggunakan wadah peta 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;
Adrian Regan
sumber
4
Bagaimana bisa peta ini lebih baik dari itu switch(n) { case XXX: return "XXX"; ... }? Manakah yang memiliki pencarian O (1) dan tidak perlu diinisialisasi? Atau apakah enum berubah entah bagaimana selama runtime?
Mainframe Nordik
Saya setuju dengan @Luther Blissett tentang penggunaan pernyataan sakelar (atau penunjuk fungsi juga)
KedarX
1
Yah, dia mungkin ingin mengeluarkan "Ini teman saya Luther adalah Kesalahan A atau" Ini teman saya Adrian adalah Kesalahan B. "Juga, menggunakan peta menghilangkan ketergantungan pada tanda tangan iostream, sehingga dia bebas menggunakannya di tempat lain kode dengan rangkaian string misalnya, string x = "Hello" + m [ErrorA], dll.
Adrian Regan
Saya yakin std :: map berisi banyak if dan switch. Saya akan membaca ini sebagai 'bagaimana saya bisa melakukan ini tanpa saya harus menulis jika dan sakelar'
Nordic Mainframe
Saya yakin ya, tetapi tentu saja Anda tidak perlu menulis skrip dalam Lua untuk menyelesaikan masalah ...
Adrian Regan
1

Untuk masalah ini, saya melakukan fungsi bantuan seperti ini:

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

Pencarian linier biasanya lebih efisien daripada std::mapuntuk koleksi kecil seperti ini.

Johan Kotlinski
sumber
1

Solusi ini tidak mengharuskan Anda menggunakan struktur data apa pun atau membuat file berbeda.

Pada dasarnya, Anda menentukan semua nilai enum Anda di #define, lalu menggunakannya di operator <<. Sangat mirip dengan jawaban @ jxh.

ideone link untuk iterasi terakhir: http://ideone.com/hQTKQp

Kode lengkap:

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

Keluaran:

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

Hal yang menyenangkan tentang melakukannya dengan cara ini adalah Anda juga dapat menentukan pesan khusus Anda sendiri untuk setiap kesalahan jika Anda merasa membutuhkannya:

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

Keluaran:

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

Jika Anda suka membuat kode / deskripsi kesalahan menjadi sangat deskriptif, Anda mungkin tidak menginginkannya dalam build produksi. Mematikannya sehingga hanya nilai yang dicetak itu mudah:

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

Keluaran:

Error: 0
Error: 1
Error: 2

Jika ini kasusnya, menemukan kesalahan nomor 525 akan menjadi PITA. Kita dapat menentukan angka secara manual di enum awal seperti ini:

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

Keluaran:

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
Xiao
sumber
0

Bagaimana dengan ini?

    enum class ErrorCodes : int{
          InvalidInput = 0
    };

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

dll ... Saya tahu ini adalah contoh yang dibuat-buat tetapi saya pikir ini memiliki aplikasi yang dapat diterapkan dan dibutuhkan dan tentunya lebih pendek daripada menulis skrip untuk itu.

pengguna633658
sumber
0

Gunakan preprocessor:

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

Keuntungan dari pendekatan ini adalah: - masih sederhana untuk dipahami, namun - memungkinkan untuk berbagai kunjungan (bukan hanya string)

Jika Anda ingin membuang yang pertama, buat makro FOREACH () untuk diri Anda sendiri, lalu #define ERROR_VALUES() (ErrorA, ErrorB, ErrorC)tulis pengunjung Anda dalam istilah FOREACH (). Kemudian coba lewati review kode :).

lorro
sumber