C ++: टेक्स्ट के रूप में enum मान प्रिंट करें


89

अगर मेरे पास इस तरह की कोई एनम है

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

फिर मैं सांत्वना के लिए प्रिंट आउट लेना चाहता हूं

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

लेकिन मैं जो चाहता हूं वह पाठ "एररएवा" है, क्या मैं इसे बिना / स्विच का उपयोग किए बिना कर सकता हूं?
और इसके लिए आपका समाधान क्या है?


मुझे लगता है कि मेरा उत्तर बहुत अच्छा है, क्या आप एक बार देख लेंगे?
जिओ


जवाबों:


63

मानचित्र का उपयोग करना:

#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। हैश-मैप का उपयोग करने के बजाय बस स्विच-केस करें। बढ़ी हुई जटिलता अच्छी बात नहीं है।
साइमन

8
अच्छी बात। अगली बार मैं करूंगा :) लेकिन अब मैं देख रहा हूं कि जिस तरह की कार्यक्षमता मैं देख रहा था, उसे जोड़ने के लिए आपने अपनी पोस्ट को पहले ही संपादित कर लिया है। बहुत बढ़िया!
साइमन

1
#p क्या है? यदि तीसरे उदाहरण में एनम के बजाय मैं एक एनम वर्ग का उपयोग करता हूं, तो क्या केवल नाम के बिना एनम स्ट्रिंग प्राप्त करना संभव है?
rh0x

2
#pप्रीप्रोसेसर स्ट्रिंग पी है। तो बुला PROCESS_VAL(ErrorA)इच्छा उत्पादन: case(ErrorA): s = "ErrorA"; break;
नाशीनस

मैं इसे एक इष्टतम समाधान के रूप में नहीं मानता: कारण: 1) मुझे दो बार उन enumमूल्यों को बनाए रखना है जो मुझे लगता है कि एक NO-GO है । 2) जब मैं समाधान को सही ढंग से समझता हूं तो यह केवल एक के लिए काम करता है enum
पीटर वर्गा '

29

मिलान मूल्यों के साथ तार की एक सरणी या वेक्टर का उपयोग करें:

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

cout << ErrorTypes[anError];

EDIT: उपरोक्त समाधान तब लागू होता है जब Enum सन्निहित होता है, अर्थात 0 से शुरू होता है और कोई असाइन किए गए मान नहीं होते हैं। यह सवाल में एनम के साथ पूरी तरह से काम करेगा।

इस मामले के लिए आगे प्रमाण के लिए कि एनम 0 से शुरू नहीं होता है, उपयोग करें:

cout << ErrorTypes[anError - ErrorA];

4
दुर्भाग्य से, एनम हमें तत्वों को मान प्रदान करने की अनुमति देता है। यदि आपके पास नॉन-कॉनग्यूयोस एनम, लाइन 'एनम स्टेटस {ओके = 0, फेल = -1, आउटऑफ मीमोरी = -2, आईऑयॉर = -1000, कन्वर्सेशन एरर = -2000) है, तो आप कैसे काम कर सकते हैं? -1001-1999 रेंज तक)
नॉर्डिक मेनफ्रेम

@ लूथर: हाँ, यह केवल सन्निहित ईर्ष्याओं के साथ काम करेगा, जो कि अधिकांश एनम हैं । इस मामले में कि एनम गैर-सन्निहित है, आपको दूसरे दृष्टिकोण, यानी नक्शे का उपयोग करने की आवश्यकता होगी। लेकिन सन्निकट एनुम के मामले में मैं इस दृष्टिकोण का उपयोग करने का सुझाव दूंगा, न कि ओवरकमप्लेट करने का।
इगोर ओक्स

2
इसलिए, यदि मेरा सहयोगी न्यूव्यू को एनम में जोड़ता है और एररटाइप्स एरे को अपडेट नहीं करता है, तो एररटाइप्स [न्यूवैल्यू] क्या पैदावार देता है? और मैं नकारात्मक एनम मूल्यों को कैसे संभालूं?
नॉर्डिक मेनफ्रेम

2
@Luther: आपको ErrorTypes को अपडेट रखना होगा। फिर, सादगी और सार्वभौमिकता के बीच एक व्यापार है, यह निर्भर करता है कि उपयोगकर्ता के लिए क्या अधिक महत्वपूर्ण है। नकारात्मक एनम मूल्यों के साथ समस्या क्या है?
इगोर ओक्स

1
स्मृति दक्षता के लिए इस सरणी को स्थिर नहीं होना चाहिए? और सुरक्षा के लिए कास्ट?
जोनाथन

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, यह समाधान किसी बाहरी उपकरण पर निर्भर नहीं है, जैसा कि ऊपर दिए गए लुआ उत्तर में है, लेकिन शुद्ध C ++ है, यह DRY सिद्धांत का अनुसरण करता है, और उपयोगकर्ता सिंटैक्स पठनीय है (यदि इसे सही ढंग से स्वरूपित किया गया है। BTW, आपको बैकस्क्रिप्स की आवश्यकता नहीं है। DEFINE_ENUM का उपयोग करते समय, जो थोड़ा अधिक प्राकृतिक दिखता है, IMO)
Fabio Fracassi

3
@ फैबियो फ्रैकासी: "यह समाधान बाहरी उपकरण पर निर्भर नहीं करता है" बूस्ट एक बाहरी उपकरण है - गैर मानक सी ++ लाइब्रेरी। इसके अलावा, यह बहुत लंबा है। किसी समस्या का समाधान यथासंभव सरल होना चाहिए। यह एक पात्रता नहीं है ...
सिग्मेट

2
वास्तव में यह आप सभी कोड के अधिकांश (वास्तव में यह सब के अलावा वास्तविक परिभाषा को छोड़कर) एक ही हेडर में रखा जा सकता है। तो यह वास्तव में यहाँ प्रस्तुत सबसे छोटा समाधान है। और बाहरी होने को बढ़ावा देने के लिए, हाँ, लेकिन स्रोत के अनुत्पादक भागों के लिए भाषा लिपि से बाहर की तुलना में कम है क्योंकि लुआ लिपि है। इसके अलावा बढ़ावा मानक के इतना करीब है कि यह हर C ++ प्रोग्रामर टूलबॉक्स में होना चाहिए। सिर्फ IMHO, ज़ाहिर है
Fabio Fracassi

[मैंने मैक्रो इनवोकेशन में नईलाइन्स के अनावश्यक भाग को हटा दिया है। उनकी जरूरत नहीं है: एक मैक्रो इनवोकेशन कई लाइनों को फैला सकता है।]
जेम्स मैकनेलिस

मैक्रो 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 ++ एनम को स्ट्रिंग में बदलने का एक सरल तरीका है?

अद्यतन: यहाँ # एक स्क्रिप्ट Lua के लिए जो एक ऑपरेटर बनाता है << प्रत्येक नाम के लिए यह मुठभेड़ों। इसे कम सरल मामलों के लिए काम करने के लिए कुछ काम की आवश्यकता हो सकती है [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' टिप्पणी करना यहाँ एक प्रथा नहीं है? बस पूछ रहा हूँ ..
नॉर्डिक मेनफ्रेम

2
मुझे लगता है कि बूस्ट पीपी समाधान नीचे (फिलिप से) बेहतर है, क्योंकि बाहरी उपकरणों का उपयोग करना बहुत महंगा रखरखाव बुद्धिमान है। लेकिन नहीं -1 क्योंकि जवाब अन्यथा मान्य है
फैबियो फ्रैकासी

4
बूस्ट पीपी भी एक रखरखाव समस्या है, क्योंकि आपको हर किसी को बूस्ट पीपी मेटलंगेज बोलने की ज़रूरत है, जो भयानक है , आसानी से टूट जाता है (आमतौर पर अनुपयोगी त्रुटि संदेश देता है) और केवल सीमित प्रयोज्य (लुआ / पायथन / पर्ल) मनमाने ढंग से कोड उत्पन्न कर सकता है। बाहरी डेटा)। यह आपके लिए निर्भरता सूची में वृद्धि को जोड़ता है, जिसे परियोजना नीति के कारण भी अनुमति नहीं दी जा सकती है। इसके अलावा, यह आक्रामक है क्योंकि इसके लिए आपको एक डीएसएल में अपने एनम को परिभाषित करना होगा। आपके पसंदीदा स्रोत कोड टूल या IDE से परेशानी हो सकती है। और अंतिम लेकिन कम से कम नहीं: आप विस्तार में एक ब्रेकपॉइंट सेट नहीं कर सकते।
नॉर्डिक मेनफ्रेम

4

जब भी मैं किसी एनम को परिभाषित करता हूं तो मैं एक स्ट्रिंग ऐरे का उपयोग करता हूं:

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;

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
क्या होगा यदि मेरी दुश्मनी 2000 से शुरू होती है? यह समाधान काम नहीं करेगा।
सीतेश

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) लुकअप है और इसे इनिशियलाइज़ करने की आवश्यकता नहीं है? या रनटाइम के दौरान किसी तरह से एनम बदलते हैं?
नॉर्डिक मेनफ्रेम

मैं स्विच स्टेटमेंट (या फ़ंक्शन पॉइंटर भी) का उपयोग करने पर @ Luther Blissett से सहमत हूं
KedarX

1
खैर, वह उत्पादन करना चाहता है "यह मेरा प्रिय मित्र लूथर एरर ए है या" यह मेरा प्रिय मित्र एड्रियन एरर बी है। "इसके अलावा, मैप का उपयोग करने से आईओस्ट्रीम हस्ताक्षरों पर निर्भरता दूर हो जाती है, जैसे कि वह कहीं और इसका उपयोग करने के लिए स्वतंत्र है। उदाहरण के लिए स्ट्रिंग संघनन के साथ कोड, स्ट्रिंग x = "हेलो" + एम [त्रुटि], आदि
एड्रियन रेगन

मुझे यकीन है कि std :: मैप में बहुत सारे आईएफ और स्विच हैं। मैं इसे 'मैं कैसे
लिखूं

मुझे यकीन है कि यह करता है, लेकिन निश्चित रूप से आपको समस्या को हल करने के लिए लूआ में एक स्क्रिप्ट लिखने की आवश्यकता नहीं है ...
एड्रियन रेगन

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 होगा। हम मैन्युअल रूप से इस तरह प्रारंभिक संख्या में संख्या निर्दिष्ट कर सकते हैं:

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

इस दृष्टिकोण का लाभ यह है कि: - यह समझना अभी भी सरल है, फिर भी - यह विभिन्न मुलाकातों (न केवल स्ट्रिंग) के लिए अनुमति देता है

यदि आप पहले ड्रॉप करने के लिए तैयार हैं, तो अपने आप को एक फॉर्च्यूनर () मैक्रो को क्राफ्ट करें, #define ERROR_VALUES() (ErrorA, ErrorB, ErrorC)और फिर फॉरएच () के संदर्भ में अपने आगंतुकों को लिखें। फिर कोड समीक्षा पास करने का प्रयास करें :)।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.