2008-10-14 19 views
104

मान लीजिए कि हमें कुछ नामित enums है:क्या सी ++ एनम स्ट्रिंग में कनवर्ट करने का कोई आसान तरीका है?

enum MyEnum { 
     FOO, 
     BAR = 0x50 
}; 

मैं के लिए क्या googled एक स्क्रिप्ट (किसी भी भाषा) है कि मेरी परियोजना में सभी हेडर स्कैन करता है और enum प्रति एक समारोह के साथ एक शीर्ष लेख उत्पन्न करता है।

char* enum_to_string(MyEnum t); 

और कुछ इस तरह के साथ एक कार्यान्वयन:

char* enum_to_string(MyEnum t){ 
     switch(t){ 
     case FOO: 
      return "FOO"; 
     case BAR: 
      return "BAR"; 
     default: 
      return "INVALID ENUM"; 
     } 
} 

पकड़ लिया typedefed enums, और बेनाम सी शैली enums के साथ वास्तव में है। क्या किसी के लिए कुछ पता है?

संपादित करें: समाधान उत्पन्न स्रोतों को छोड़कर, मेरे स्रोत को संशोधित नहीं करना चाहिए। Enums एक एपीआई में हैं, तो अब तक प्रस्तावित समाधान का उपयोग सिर्फ एक विकल्प नहीं है।

+0

संभावित डुप्लिकेट [सी में स्ट्रिंग के रूप में enum प्रकारों के चर का उपयोग करने का आसान तरीका?] (Http://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types- as-string-in-c) – karlphillip

+0

मैक्रो आधारित फैक्ट्री के बारे में उत्तर http://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types-as-string-in- सी # 202511 - प्रश्न अद्यतन होने के बाद, यह अब प्रासंगिक नहीं है। – Suma

उत्तर

45

आप GCCXML की जाँच करने के लिए चाहते हो सकता है के लिए के परिभाषित शामिल कर सकते हैं। अपने नमूना कोड पर

रनिंग GCCXML पैदा करता है:

<GCC_XML> 
    <Namespace id="_1" name="::" members="_3 " mangled="_Z2::"/> 
    <Namespace id="_2" name="std" context="_1" members="" mangled="_Z3std"/> 
    <Enumeration id="_3" name="MyEnum" context="_1" location="f0:1" file="f0" line="1"> 
    <EnumValue name="FOO" init="0"/> 
    <EnumValue name="BAR" init="80"/> 
    </Enumeration> 
    <File id="f0" name="my_enum.h"/> 
</GCC_XML> 

आप गणन और EnumValue टैग बाहर निकालते हैं और अपने वांछित कोड उत्पन्न करने के लिए पसंद करते हैं किसी भी भाषा इस्तेमाल कर सकते हैं।

+0

उत्कृष्ट! एक साधारण पायथन लिपि के साथ एक आकर्षण के रूप में काम किया। धन्यवाद। –

+6

+1, जीसीसीएक्सएमएल बहुत अच्छा लग रहा है! (हालांकि मैं लगभग 1 वर्ष के रूप में शुरू हुआ था क्योंकि मैंने शुरुआती वर्बोज़ एक्सएमएल सिंटैक्स का उपयोग अपने enum को एन्कोड करने के लिए एक सुझाव के रूप में गलत तरीके से किया था - एक समाधान जो overengineering की reeks!) –

+1

कोई बदलाव आप पाइथन लिपि पोस्ट कर सकते हैं? – phillipwei

0

यह बहुत ही आसान तरीका है (स्ट्रिंग की एक सरणी भी काम कर सकती है)।

समस्या यह है कि एक बार सी प्रोग्राम संकलित हो जाने के बाद, enum का बाइनरी मान सब कुछ उपयोग किया जाता है, और नाम समाप्त हो गया है।

29

मुझे जो करना है वह एक सी सरणी है जो नामों के साथ समान क्रम और स्थिति के रूप में है।

उदाहरण के लिए।

enum colours { red, green, blue }; 
const char *colour_names[] = { "red", "green", "blue" }; 

तो आप स्थानों में सरणी का उपयोग कर सकते हैं जहाँ आप एक मानव पठनीय मूल्य चाहते हैं, जैसे

colours mycolour = red; 
cout << "the colour is" << colour_names[mycolour]; 

आप stringizing ऑपरेटर (देखें अपने पूर्वप्रक्रमक संदर्भ में #) के साथ एक छोटे से प्रयोग कर सकता है कि कुछ परिस्थितियों में आप जो चाहते हैं वह करेंगे- उदाहरण:

#define printword(XX) cout << #XX; 
printword(red); 

stdout पर "लाल" प्रिंट करेगा। दुर्भाग्य से यह एक चर के लिए काम नहीं करेगा (जैसा कि आपको परिवर्तनीय नाम मुद्रित किया जाएगा)

+0

अंतिम चेतावनी (एक चर के लिए काम नहीं करेगा) एक बड़ी कमी है, लेकिन वैसे भी +1। – chappjc

+2

केवल तभी काम करता है जब आप प्रविष्टियों के लिए विशेष संख्यात्मक मान निर्धारित नहीं करेंगे। – kyb

1

उत्तर 0 के साथ एक समस्या यह है कि enum बाइनरी मान आवश्यक रूप से 0 से शुरू नहीं होते हैं और आवश्यक रूप से संगत नहीं होते हैं।

जब मैं इस की जरूरत है, मैं आमतौर पर:

  • enum परिभाषा मेरे स्रोत में खींच
  • संपादित करें यह सिर्फ नाम पाने के लिए
  • में मामला खंड के नाम बदलने के लिए एक मैक्रो करना प्रश्न, हालांकि आम तौर पर एक पंक्ति पर: केस foo: वापसी "foo";
  • स्विच, डिफ़ॉल्ट और अन्य वाक्य रचना यह कानूनी
68

एक्स मैक्रो सबसे अच्छा समाधान कर रहे हैं बनाने के लिए जोड़ सकते हैं। उदाहरण:

#include <iostream> 

enum Colours { 
# define X(a) a, 
# include "colours.def" 
# undef X 
    ColoursCount 
}; 

char const* const colours_str[] = { 
# define X(a) #a, 
# include "colours.def" 
# undef X 
    0 
}; 

std::ostream& operator<<(std::ostream& os, enum Colours c) 
{ 
    if (c >= ColoursCount || c < 0) return os << "???"; 
    return os << colours_str[c]; 
} 

int main() 
{ 
    std::cout << Red << Blue << Green << Cyan << Yellow << Magenta << std::endl; 
} 

रंग।def:

X(Red) 
X(Green) 
X(Blue) 
X(Cyan) 
X(Yellow) 
X(Magenta) 

हालांकि, मैं आमतौर पर निम्न विधि पसंद करता हूं, ताकि स्ट्रिंग को थोड़ा सा ट्विक करना संभव हो।

#define X(a, b) a, 
#define X(a, b) b, 

X(Red, "red") 
X(Green, "green") 
// etc. 
+11

निफ्टी, हालांकि मुझे अतिरिक्त फ़ाइल –

+0

+1 पसंद नहीं है, लेकिन इंटेलिसेंस के साथ गड़बड़ होने की संभावना है, और इस तरह की चीजें ... –

+2

बस सुनिश्चित करें कि आपकी बिल्ड प्रक्रिया प्रत्येक शामिल होने से पहले #pragma (एक बार) पूर्ववत नहीं करेगी फ़ाइल ... – xtofl

3

Suma's macro solution अच्छा है। हालांकि, आपको दो अलग-अलग मैक्रो की आवश्यकता नहीं है। सी ++ खुशी से दो बार एक हेडर शामिल करें। बस गार्ड शामिल छोड़ दें।

तो तुम एक foobar.h सिर्फ

ENUM(Foo, 1) 
ENUM(Bar, 2) 

को परिभाषित करना होगा और आप इसे इस तरह से शामिल होंगे:

#define ENUMFACTORY_ARGUMENT "foobar.h" 
#include "enumfactory.h" 

enumfactory.h 2 #include ENUMFACTORY_ARGUMENT रों करेंगे। पहले दौर में, यह Suma के DECLARE_ENUM की तरह ENUM का विस्तार करता है; दूसरे दौर में ENUM DEFINE_ENUM की तरह काम करता है।

आप enumfactory.h कई बार, भी, जब तक कि आप अलग अलग # में पारित ENUMFACTORY_ARGUMENT

+0

ऐसा लगता है जैसे सुमा ने जवाब दिया [यहां] (https://stackoverflow.com/questions/147267/easy-way-to-use -variables के- enum प्रकार के रूप में स्ट्रिंग-इन-सी # 202,511)। आप अपने उत्तर में लिंक शामिल करना चाह सकते हैं। मुझे केवल मौका और बुद्धिमान सुमास द्वारा टिप्पणी मिली है, यह उत्तरदायी है – user463035818

2

ध्यान दें कि आपका रूपांतरण फ़ंक्शन आदर्श रूप से कॉन्स char * लौटा रहा है।

आप अपने-अपने अलग हेडर फाइल में अपनी enums डाल करने के लिए खर्च कर सकते हैं, तो आप शायद मैक्रो के साथ कुछ इस तरह (ओह, यह बदसूरत हो जाएगा) कर सकता है:

#include "enum_def.h" 
#include "colour.h" 
#include "enum_conv.h" 
#include "colour.h" 

enum_def.h है कहां:

#undef ENUM_START 
#undef ENUM_ADD 
#undef ENUM_END 
#define ENUM_START(NAME) enum NAME { 
#define ENUM_ADD(NAME, VALUE) NAME = VALUE, 
#define ENUM_END }; 

और enum_conv.h है:

#undef ENUM_START 
#undef ENUM_ADD 
#undef ENUM_END 
#define ENUM_START(NAME) const char *##NAME##_to_string(NAME val) { switch (val) { 
#define ENUM_ADD(NAME, VALUE) case NAME: return #NAME; 
#define ENUM_END default: return "Invalid value"; } } 

और अंत में, colour.h है:

ENUM_START(colour) 
ENUM_ADD(red, 0xff0000) 
ENUM_ADD(green, 0x00ff00) 
ENUM_ADD(blue, 0x0000ff) 
ENUM_END 

और आप के रूप में रूपांतरण समारोह का उपयोग कर सकते हैं:

printf("%s", colour_to_string(colour::red)); 

यह बदसूरत है, लेकिन यह एक ही रास्ता (पूर्वप्रक्रमक स्तर पर) है तो आप सिर्फ एक ही स्थान पर अपने enum परिभाषित करने देता है कि तुम्हारा कोड। इसलिए आपका कोड enum में संशोधन के कारण त्रुटियों के लिए प्रवण नहीं है। आपकी enum परिभाषा और रूपांतरण फ़ंक्शन हमेशा समन्वयित रहेगा। हालांकि, मैं फिर कहता हूँ, इस बदसूरत है :)

1

निम्नलिखित रूबी स्क्रिप्ट हेडर पार्स करने के लिए प्रयास करता है और मूल हेडर के साथ-साथ आवश्यक स्रोतों builts।

#! /usr/bin/env ruby 

# Let's "parse" the headers 
# Note that using a regular expression is rather fragile 
# and may break on some inputs 

GLOBS = [ 
    "toto/*.h", 
    "tutu/*.h", 
    "tutu/*.hxx" 
] 

enums = {} 
GLOBS.each { |glob| 
    Dir[glob].each { |header| 
    enums[header] = File.open(header, 'rb') { |f| 
     f.read 
    }.scan(/enum\s+(\w+)\s+\{\s*([^}]+?)\s*\}/m).collect { |enum_name, enum_key_and_values| 
     [ 
     enum_name, enum_key_and_values.split(/\s*,\s*/).collect { |enum_key_and_value| 
      enum_key_and_value.split(/\s*=\s*/).first 
     } 
     ] 
    } 
    } 
} 


# Now we build a .h and .cpp alongside the parsed headers 
# using the template engine provided with ruby 
require 'erb' 

template_h = ERB.new <<-EOS 
#ifndef <%= enum_name %>_to_string_h_ 
#define <%= enum_name %>_to_string_h_ 1 

#include "<%= header %>" 
char* enum_to_string(<%= enum_name %> e); 

#endif 
EOS 

template_cpp = ERB.new <<-EOS 
#include "<%= enum_name %>_to_string.h" 

char* enum_to_string(<%= enum_name %> e) 
{ 
    switch (e) 
    {<% enum_keys.each do |enum_key| %> 
    case <%= enum_key %>: return "<%= enum_key %>";<% end %> 
    default: return "INVALID <%= enum_name %> VALUE"; 
    } 
} 
EOS 

enums.each { |header, enum_name_and_keys| 
    enum_name_and_keys.each { |enum_name, enum_keys| 
    File.open("#{File.dirname(header)}/#{enum_name}_to_string.h", 'wb') { |built_h| 
     built_h.write(template_h.result(binding)) 
    } 

    File.open("#{File.dirname(header)}/#{enum_name}_to_string.cpp", 'wb') { |built_cpp| 
     built_cpp.write(template_cpp.result(binding)) 
    } 
    } 
} 

नियमित अभिव्यक्ति का उपयोग करते हुए इस "पार्सर" काफी नाजुक है, यह शान से अपने विशिष्ट हेडर को संभालने में सक्षम नहीं हो सकता है बनाता है।

मान लीजिए कि आपके पास हेडर टू ए/एचएच है, जिसमें माईएनम और मायनम 2 के लिए परिभाषाएं हैं। स्क्रिप्ट का निर्माण होगा:

toto/MyEnum_to_string.h 
toto/MyEnum_to_string.cpp 
toto/MyEnum2_to_string.h 
toto/MyEnum2_to_string.cpp 

अधिक मजबूत समाधान होगा:

  • बिल्ड सभी स्रोतों किसी अन्य स्रोत से enums और उनके कार्यों को परिभाषित। इसका मतलब है कि आप अपने एनम्स को एक्सएमएल/वाईएमएल/जो भी फाइल में सी/सी ++ से पार्स करना आसान है, में परिभाषित करेंगे।
  • अवीडी द्वारा सुझाए गए वास्तविक कंपाइलर का उपयोग करें।
  • टेम्पलेट्स के साथ या बिना प्रीप्रोसेसर मैक्रोज़ का उपयोग करें।
2

एक अन्य जवाब: कुछ संदर्भों में, यह समझ में आता है एक सीएसवी, YAML, या एक्सएमएल फ़ाइल की तरह, एक गैर कोड प्रारूप में अपने गणन परिभाषित करते हैं, और फिर दोनों सी ++ गणन कोड और को-स्ट्रिंग उत्पन्न करने के लिए परिभाषा से कोड। यह दृष्टिकोण आपके आवेदन में व्यावहारिक नहीं हो सकता है या नहीं, लेकिन यह ध्यान में रखना कुछ है।

8

क्यूटी खींचने के लिए है कि (मेटा वस्तु संकलक करने के लिए धन्यवाद) के सक्षम है: link

2

मैं अलग पक्ष-साथ enum आवरण वर्ग है जो मैक्रो के साथ उत्पन्न कर रहे हैं के साथ ऐसा कर। वहाँ कई फायदे हैं:

  • उन्हें उत्पन्न कर सकता हूँ enums के लिए मैं परिभाषित नहीं करते (जैसे: ओएस मंच हैडर enums)
  • रेंज आवरण वर्ग
  • में जाँच कर सकते हैं "होशियार" के साथ प्रारूपित को शामिल कर सकते हैं बिट फील्ड एनम्स

निस्संदेह यह है कि मुझे फॉर्मेटर कक्षाओं में enum मानों को डुप्लिकेट करने की आवश्यकता है, और मेरे पास उत्पन्न करने के लिए कोई स्क्रिप्ट नहीं है। इसके अलावा, हालांकि, यह बहुत अच्छी तरह से काम करता प्रतीत होता है।

यहाँ जो मैक्रो और टेम्पलेट्स को लागू करता है मेरी codebase, बिना सब ढांचे संहिता से enum का एक उदाहरण है, लेकिन आप अनुमान लगा सकते हैं:

enum EHelpLocation 
{ 
    HELP_LOCATION_UNKNOWN = 0, 
    HELP_LOCAL_FILE   = 1, 
    HELP_HTML_ONLINE  = 2, 
}; 
class CEnumFormatter_EHelpLocation : public CEnumDefaultFormatter<EHelpLocation> 
{ 
public: 
    static inline CString FormatEnum(EHelpLocation eValue) 
    { 
     switch (eValue) 
     { 
      ON_CASE_VALUE_RETURN_STRING_OF_VALUE(HELP_LOCATION_UNKNOWN); 
      ON_CASE_VALUE_RETURN_STRING_OF_VALUE(HELP_LOCAL_FILE); 
      ON_CASE_VALUE_RETURN_STRING_OF_VALUE(HELP_HTML_ONLINE); 
     default: 
      return FormatAsNumber(eValue); 
     } 
    } 
}; 
DECLARE_RANGE_CHECK_CLASS(EHelpLocation, CRangeInfoSequential<HELP_HTML_ONLINE>); 
typedef ESmartEnum< EHelpLocation, HELP_LOCATION_UNKNOWN, CEnumFormatter_EHelpLocation, CRangeInfo_EHelpLocation > SEHelpLocation; 

विचार तो बजाय EHelpLocation का उपयोग करने का है, तो आप SEHelpLocation का उपयोग करें; सबकुछ एक ही काम करता है, लेकिन आपको एनम वैरिएबल पर रेंज जांच और 'फॉर्मेट()' विधि मिलती है। यदि आपको स्टैंड-अलोन मान को प्रारूपित करने की आवश्यकता है, तो आप CEnumFormatter_EHelpLocation :: FormatEnum (...) का उपयोग कर सकते हैं।

आशा है कि यह सहायक होगा। मुझे एहसास है कि यह वास्तव में अन्य वर्ग उत्पन्न करने के लिए एक स्क्रिप्ट के मूल प्रश्न को भी संबोधित नहीं करता है, लेकिन मुझे आशा है कि संरचना किसी को भी एक ही समस्या को हल करने की कोशिश करने में मदद करेगी, या ऐसी स्क्रिप्ट लिखें।

38

@hydroo: अतिरिक्त फ़ाइल के बिना:

#define SOME_ENUM(DO) \ 
    DO(Foo) \ 
    DO(Bar) \ 
    DO(Baz) 

#define MAKE_ENUM(VAR) VAR, 
enum MetaSyntacticVariable{ 
    SOME_ENUM(MAKE_ENUM) 
}; 

#define MAKE_STRINGS(VAR) #VAR, 
const char* const MetaSyntacticVariableNames[] = { 
    SOME_ENUM(MAKE_STRINGS) 
}; 
+0

मुझे इस समाधान से प्यार है। यह स्पष्ट होगा अगर SOME_UNION और MAKE_UNION को SOME_ENUM और MAKE_ENUM कहा जाता था, हालांकि। –

+0

यह एक अच्छा समाधान है। मेरे पास सबसे अधिक बनाए रखने योग्य सी ++ संसाधन प्रबंधक है जिसे मैंने कभी निपटाया है। – DCurro

+0

मुझे इस सरल समाधान के लिए आपको धन्यवाद देना चाहिए :-) - मैंने थोड़ा सा संशोधित किया है, 'मेटासिंक्टैक्टिक वैरिएबल नाम []' एक क्लास घोषणापत्र का हिस्सा बनने के लिए, 'स्थिर कॉन्स char * getNameByEnum (मेटासिंक्टैक्टिक वैरिएबल ई) {/ * स्थिर स्ट्रिंग को वापस करने के लिए कोड * /} ' – DeckerDK

5

दिलचस्प तरीके की संख्या को देखने के लिए। यहां एक है जिसे मैंने बहुत समय पहले इस्तेमाल किया था:

फ़ाइल myenummap में।ज:

#include <map> 
#include <string> 
enum test{ one, two, three, five=5, six, seven }; 
struct mymap : std::map<unsigned int, std::string> 
{ 
    mymap() 
    { 
    this->operator[](one) = "ONE"; 
    this->operator[](two) = "TWO"; 
    this->operator[](three) = "THREE"; 
    this->operator[](five) = "FIVE"; 
    this->operator[](six) = "SIX"; 
    this->operator[](seven) = "SEVEN"; 
    }; 
    ~mymap(){}; 
}; 

main.cpp में स्थिरांक

#include "myenummap.h" 

... 
mymap nummap; 
std::cout<< nummap[ one ] << std::endl; 

इसकी नहीं है, लेकिन इसके सुविधाजनक।

यहां एक और तरीका है जो सी ++ 11 सुविधाओं का उपयोग करता है। यह स्थिरांक है, एक एसटीएल कंटेनर के वारिस नहीं है और एक छोटे से tidier है:

#include <vector> 
#include <string> 
#include <algorithm> 
#include <iostream> 

//These stay together and must be modified together 
enum test{ one, two, three, five=5, six, seven }; 
std::string enum_to_str(test const& e) 
{ 
    typedef std::pair<int,std::string> mapping; 
    auto m = [](test const& e,std::string const& s){return mapping(static_cast<int>(e),s);}; 
    std::vector<mapping> const nummap = 
    { 
     m(one,"one"), 
     m(two,"two"), 
     m(three,"three"), 
     m(five,"five"), 
     m(six,"six"), 
     m(seven,"seven"), 
    }; 
    for(auto i : nummap) 
    { 
     if(i.first==static_cast<int>(e)) 
     { 
      return i.second; 
     } 
    } 
    return ""; 
} 

int main() 
{ 
// std::cout<< enum_to_str(46) << std::endl; //compilation will fail 
    std::cout<< "Invalid enum to string : [" << enum_to_str(test(46)) << "]"<<std::endl; //returns an empty string 
    std::cout<< "Enumval five to string : ["<< enum_to_str(five) << "] "<< std::endl; //works 
    return 0; 
} 
+10

एक एसएलएल कंटेनर को लेना अच्छा विचार नहीं है –

+1

यह पूरी तरह से कानूनी है। मुझे हर व़क्त यह करना है। –

+0

अच्छा समाधान। यह सी ++ है इसलिए एसएलएल मानचित्र का उपयोग करना ठीक है। –

1

यह अप्रकाशित सॉफ्टवेयर है, लेकिन यह फ्रैंक Laub से BOOST_ENUM लगता बिल फिट सकता। मुझे जो हिस्सा पसंद है वह यह है कि आप एक वर्ग के दायरे में एक enum परिभाषित कर सकते हैं जो अधिकांश मैक्रो आधारित enums आमतौर पर आपको करने की अनुमति नहीं देते हैं। यह बूस्ट वॉल्ट में स्थित है: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=enum_rev4.6.zip&directory=& इसने 2006 से कोई विकास नहीं देखा है, इसलिए मुझे नहीं पता कि यह नई बूस्ट रिलीज़ के साथ कितनी अच्छी तरह संकलित है। उपयोग के उदाहरण के लिए libs/test के अंतर्गत देखें।

0

यहां एक सीएलआई प्रोग्राम है जिसे मैंने आसानी से स्ट्रिंग में enums रूपांतरित करने के लिए लिखा था। इसका उपयोग करना आसान है, और इसे पूरा करने के लिए लगभग 5 सेकंड लगते हैं (प्रोग्राम युक्त निर्देशिका में सीडी के समय सहित, फिर इसे चलाएं, इसे एनम युक्त फ़ाइल में पास करें)।

यहाँ डाउनलोड करें: http://www.mediafire.com/?nttignoozzz

चर्चा विषय इस पर यहाँ: http://cboard.cprogramming.com/projects-job-recruitment/127488-free-program-im-sharing-convertenumtostrings.html

रन "--help" तर्क के साथ कार्यक्रम एक वर्णन है कि यह कैसे उपयोग करने के लिए मिलता है।

+0

क्या आप इसे किसी भंडार पर कहीं भी रख सकते हैं (github, google code या bitbucket) और मीडियाफ़ीयर के बजाय यहां लिंक पोस्ट करें? मैं इसे समझने के इच्छुक लोगों की मदद करूंगा :) –

+0

ठीक है, यहां Google कोड लिंक है: http://code.google.com/p/convertenumtostrings/ –

7

मैंने आज इस चक्र का पुन: आविष्कार किया, और सोचा कि मैं इसे साझा करूंगा।

इस कार्यान्वयन करता नहीं कोड कि स्थिरांक है, जो enumerations या #define रों या कुछ और कि एक पूर्णांक के लिए devolves हो सकता है परिभाषित करता है के लिए किसी भी परिवर्तन की आवश्यकता - मेरे मामले में मैं प्रतीकों अन्य प्रतीक के रूप में परिभाषित किया था। यह स्पैस मूल्यों के साथ भी अच्छी तरह से काम करता है। यह एक ही मूल्य के लिए कई नामों को भी अनुमति देता है, हमेशा पहले को लौटता है। केवल नकारात्मक पक्ष यह है कि आपको स्थिरांक की एक तालिका बनाने की आवश्यकता होती है, जो कि पुराने हो सकता है क्योंकि उदाहरण के लिए नए जोड़े गए हैं।

struct IdAndName 
{ 
    int   id; 
    const char * name; 
    bool operator<(const IdAndName &rhs) const { return id < rhs.id; } 
}; 
#define ID_AND_NAME(x) { x, #x } 

const char * IdToName(int id, IdAndName *table_begin, IdAndName *table_end) 
{ 
    if ((table_end - table_begin) > 1 && table_begin[0].id > table_begin[1].id) 
     std::stable_sort(table_begin, table_end); 

    IdAndName searchee = { id, NULL }; 
    IdAndName *p = std::lower_bound(table_begin, table_end, searchee); 
    return (p == table_end || p->id != id) ? NULL : p->name; 
} 

template<int N> 
const char * IdToName(int id, IdAndName (&table)[N]) 
{ 
    return IdToName(id, &table[0], &table[N]); 
} 

कैसे आप इसका उपयोग का एक उदाहरण:

static IdAndName WindowsErrorTable[] = 
{ 
    ID_AND_NAME(INT_MAX),    // flag value to indicate unsorted table 
    ID_AND_NAME(NO_ERROR), 
    ID_AND_NAME(ERROR_INVALID_FUNCTION), 
    ID_AND_NAME(ERROR_FILE_NOT_FOUND), 
    ID_AND_NAME(ERROR_PATH_NOT_FOUND), 
    ID_AND_NAME(ERROR_TOO_MANY_OPEN_FILES), 
    ID_AND_NAME(ERROR_ACCESS_DENIED), 
    ID_AND_NAME(ERROR_INVALID_HANDLE), 
    ID_AND_NAME(ERROR_ARENA_TRASHED), 
    ID_AND_NAME(ERROR_NOT_ENOUGH_MEMORY), 
    ID_AND_NAME(ERROR_INVALID_BLOCK), 
    ID_AND_NAME(ERROR_BAD_ENVIRONMENT), 
    ID_AND_NAME(ERROR_BAD_FORMAT), 
    ID_AND_NAME(ERROR_INVALID_ACCESS), 
    ID_AND_NAME(ERROR_INVALID_DATA), 
    ID_AND_NAME(ERROR_INVALID_DRIVE), 
    ID_AND_NAME(ERROR_CURRENT_DIRECTORY), 
    ID_AND_NAME(ERROR_NOT_SAME_DEVICE), 
    ID_AND_NAME(ERROR_NO_MORE_FILES) 
}; 

const char * error_name = IdToName(GetLastError(), WindowsErrorTable); 

IdToName समारोह std::lower_bound पर निर्भर करता है जल्दी लुकअप, जो मेज अनुसार क्रमबद्ध करने की आवश्यकता है क्या करना है। यदि तालिका में पहली दो प्रविष्टियां क्रम से बाहर हैं, तो फ़ंक्शन इसे स्वचालित रूप से सॉर्ट करेगा।

संपादित करें: एक टिप्पणी ने मुझे एक ही सिद्धांत का उपयोग करने का एक और तरीका बताया है। एक मैक्रो एक बड़े switch कथन की पीढ़ी को सरल बनाता है।

#define ID_AND_NAME(x) case x: return #x 

const char * WindowsErrorToName(int id) 
{ 
    switch(id) 
    { 
     ID_AND_NAME(ERROR_INVALID_FUNCTION); 
     ID_AND_NAME(ERROR_FILE_NOT_FOUND); 
     ID_AND_NAME(ERROR_PATH_NOT_FOUND); 
     ID_AND_NAME(ERROR_TOO_MANY_OPEN_FILES); 
     ID_AND_NAME(ERROR_ACCESS_DENIED); 
     ID_AND_NAME(ERROR_INVALID_HANDLE); 
     ID_AND_NAME(ERROR_ARENA_TRASHED); 
     ID_AND_NAME(ERROR_NOT_ENOUGH_MEMORY); 
     ID_AND_NAME(ERROR_INVALID_BLOCK); 
     ID_AND_NAME(ERROR_BAD_ENVIRONMENT); 
     ID_AND_NAME(ERROR_BAD_FORMAT); 
     ID_AND_NAME(ERROR_INVALID_ACCESS); 
     ID_AND_NAME(ERROR_INVALID_DATA); 
     ID_AND_NAME(ERROR_INVALID_DRIVE); 
     ID_AND_NAME(ERROR_CURRENT_DIRECTORY); 
     ID_AND_NAME(ERROR_NOT_SAME_DEVICE); 
     ID_AND_NAME(ERROR_NO_MORE_FILES); 
     default: return NULL; 
    } 
} 
+0

अच्छा समाधान। लेकिन मेरे लिए मैं 'स्विच और केस' पसंद करूंगा क्योंकि यह समझना आसान और आसान है। – Deqing

6
#define stringify(name) # name 

enum MyEnum { 
    ENUMVAL1 
}; 
...stuff... 

stringify(EnumName::ENUMVAL1); // Returns MyEnum::ENUMVAL1 

Further discussion on this method

Preprocessor directive tricks for newcomers

+0

यह वास्तव में अधिक वोट होना चाहिए। – AzP

+3

दरअसल यह काफी बेकार है, क्योंकि स्ट्रिंग विधि विधि संकलित समय पर है और यह काफी शाब्दिक है। यदि आप कहते हैं कि एक चर के अंदर प्रश्न में enum प्रकार है, तो चर को स्ट्रिंग करने का प्रयास करने से आपको वैरिएबल नाम मिलेगा, न कि enum प्रकार का नाम। – srcspider

0

नहीं इतनी देर पहले मैं enums ठीक से QComboBox में प्रदर्शित करने के लिए और एक बयान

के रूप में enum और स्ट्रिंग अभ्यावेदन की परिभाषा के लिए कुछ चाल बनाया
#pragma once 
#include <boost/unordered_map.hpp> 

namespace enumeration 
{ 

    struct enumerator_base : boost::noncopyable 
    { 
     typedef 
     boost::unordered_map<int, std::wstring> 
     kv_storage_t; 
     typedef 
     kv_storage_t::value_type 
     kv_type; 
     kv_storage_t const & kv() const 
     { 
     return storage_; 
     } 

     LPCWSTR name(int i) const 
     { 
     kv_storage_t::const_iterator it = storage_.find(i); 
     if(it != storage_.end()) 
      return it->second.c_str(); 
     return L"empty"; 
     } 

    protected: 
     kv_storage_t storage_; 
    }; 

    template<class T> 
    struct enumerator; 

    template<class D> 
    struct enum_singleton : enumerator_base 
    { 
     static enumerator_base const & instance() 
     { 
     static D inst; 
     return inst; 
     } 
    }; 
} 

#define QENUM_ENTRY(K, V, N) K, N storage_.insert(std::make_pair((int)K, V)); 

#define QBEGIN_ENUM(NAME, C) \ 
enum NAME      \ 
{        \ 
    C       \ 
}        \ 
};       \ 
}        \ 

#define QEND_ENUM(NAME) \ 
};      \ 
namespace enumeration \ 
{      \ 
template<>    \ 
struct enumerator<NAME>\ 
    : enum_singleton< enumerator<NAME> >\ 
{      \ 
    enumerator()  \ 
    { 

//usage 
/* 
QBEGIN_ENUM(test_t, 
    QENUM_ENTRY(test_entry_1, L"number uno", 
    QENUM_ENTRY(test_entry_2, L"number dos", 
    QENUM_ENTRY(test_entry_3, L"number tres", 
QEND_ENUM(test_t))))) 
*/ 

अब आपके पास 01 हैenums को स्ट्रिंग में कनवर्ट करने में सक्षम है। यदि आप kv_storage_t को boost::bimap के साथ प्रतिस्थापित करते हैं, तो आप पिछड़े रूपांतरण भी कर पाएंगे। कनवर्टर के लिए आम आधार वर्ग क्यूटी वस्तु में संग्रहीत करना शुरू की गई थी, क्योंकि क्यूटी वस्तुओं टेम्पलेट्स नहीं किया जा सका

Previous appearance

0

संस्करण के रूप में, सरल lib>http://codeproject.com/Articles/42035/Enum-to-String-and-Vice-Versa-in-C

का उपयोग कोड में

#include <EnumString.h> 

enum FORM { 
    F_NONE = 0, 
    F_BOX, 
    F_CUBE, 
    F_SPHERE, 
}; 

ऐड लाइनों

Begin_Enum_String(FORM) 
{ 
    Enum_String(F_NONE); 
    Enum_String(F_BOX); 
    Enum_String(F_CUBE); 
    Enum_String(F_SPHERE); 
} 
End_Enum_String; 

कार्य ठीक है, यदि enum में मान गणराज्य नहीं हैं।

उदाहरण उपयोग

enum FORM f = ... 
const std::string& str = EnumString<FORM>::From(f); 

और इसके विपरीत

assert(EnumString<FORM>::To(f, str)); 
4
#include <stdarg.h> 
#include <algorithm> 
#include <string> 
#include <vector> 
#include <sstream> 
#include <map> 

#define SMART_ENUM(EnumName, ...)         \ 
class EnumName              \ 
{                 \ 
private:               \ 
    static std::map<int, std::string> nameMap;      \ 
public:                \ 
    enum {__VA_ARGS__};            \ 
private:               \ 
    static std::map<int, std::string> initMap()      \ 
    {                \ 
     using namespace std;          \ 
                    \ 
     int val = 0;            \ 
     string buf_1, buf_2, str = #__VA_ARGS__;     \ 
     replace(str.begin(), str.end(), '=', ' ');     \ 
     stringstream stream(str);         \ 
     vector<string> strings;          \ 
     while (getline(stream, buf_1, ','))       \ 
      strings.push_back(buf_1);        \ 
     map<int, string> tmp;          \ 
     for(vector<string>::iterator it = strings.begin();   \ 
               it != strings.end(); \ 
               ++it)    \ 
     {               \ 
      buf_1.clear(); buf_2.clear();       \ 
      stringstream localStream(*it);       \ 
      localStream>> buf_1 >> buf_2;       \ 
      if(buf_2.size() > 0)         \ 
       val = atoi(buf_2.c_str());       \ 
      tmp[val++] = buf_1;          \ 
     }               \ 
     return tmp;             \ 
    }                \ 
public:                \ 
    static std::string toString(int aInt)       \ 
    {                \ 
     return nameMap[aInt];          \ 
    }                \ 
};                 \ 
std::map<int, std::string>           \ 
EnumName::nameMap = EnumName::initMap(); 

उपयोग:

SMART_ENUM(MyEnum, ONE=1, TWO, THREE, TEN=10, ELEVEN) 
cout<<MyEnum::toString(MyEnum::TWO); 
cout<<MyEnum::toString(10); 
+1

मुझे आपकी एपीआई पसंद है, लेकिन दुर्भाग्यवश, आपका स्मार्टएनम वास्तव में एक enum "type" नहीं बनाता है। आप 'MyEnum x = MyEnum :: TWO;' नहीं कर सकते। मैंने इसका समर्थन करने के लिए अपनी कक्षा का अपना संपादन पोस्ट कर दिया है। –

0

यहाँ < < और >> ई पर धारा ऑपरेटरों प्राप्त करने का प्रयास है संख्या स्वचालित रूप से एक एक पंक्ति मैक्रो आदेश के साथ ही ...

परिभाषाएं:

#include <string> 
#include <iostream> 
#include <stdexcept> 
#include <algorithm> 
#include <iterator> 
#include <sstream> 
#include <vector> 

#define MAKE_STRING(str, ...) #str, MAKE_STRING1_(__VA_ARGS__) 
#define MAKE_STRING1_(str, ...) #str, MAKE_STRING2_(__VA_ARGS__) 
#define MAKE_STRING2_(str, ...) #str, MAKE_STRING3_(__VA_ARGS__) 
#define MAKE_STRING3_(str, ...) #str, MAKE_STRING4_(__VA_ARGS__) 
#define MAKE_STRING4_(str, ...) #str, MAKE_STRING5_(__VA_ARGS__) 
#define MAKE_STRING5_(str, ...) #str, MAKE_STRING6_(__VA_ARGS__) 
#define MAKE_STRING6_(str, ...) #str, MAKE_STRING7_(__VA_ARGS__) 
#define MAKE_STRING7_(str, ...) #str, MAKE_STRING8_(__VA_ARGS__) 
#define MAKE_STRING8_(str, ...) #str, MAKE_STRING9_(__VA_ARGS__) 
#define MAKE_STRING9_(str, ...) #str, MAKE_STRING10_(__VA_ARGS__) 
#define MAKE_STRING10_(str) #str 

#define MAKE_ENUM(name, ...) MAKE_ENUM_(, name, __VA_ARGS__) 
#define MAKE_CLASS_ENUM(name, ...) MAKE_ENUM_(friend, name, __VA_ARGS__) 

#define MAKE_ENUM_(attribute, name, ...) name { __VA_ARGS__ }; \ 
    attribute std::istream& operator>>(std::istream& is, name& e) { \ 
     const char* name##Str[] = { MAKE_STRING(__VA_ARGS__) }; \ 
     std::string str; \ 
     std::istream& r = is >> str; \ 
     const size_t len = sizeof(name##Str)/sizeof(name##Str[0]); \ 
     const std::vector<std::string> enumStr(name##Str, name##Str + len); \ 
     const std::vector<std::string>::const_iterator it = std::find(enumStr.begin(), enumStr.end(), str); \ 
     if (it != enumStr.end())\ 
      e = name(it - enumStr.begin()); \ 
     else \ 
      throw std::runtime_error("Value \"" + str + "\" is not part of enum "#name); \ 
     return r; \ 
    }; \ 
    attribute std::ostream& operator<<(std::ostream& os, const name& e) { \ 
     const char* name##Str[] = { MAKE_STRING(__VA_ARGS__) }; \ 
     return (os << name##Str[e]); \ 
    } 

उपयोग:

// Declare global enum 
enum MAKE_ENUM(Test3, Item13, Item23, Item33, Itdsdgem43); 

class Essai { 
public: 
    // Declare enum inside class 
    enum MAKE_CLASS_ENUM(Test, Item1, Item2, Item3, Itdsdgem4); 

}; 

int main() { 
    std::cout << Essai::Item1 << std::endl; 

    Essai::Test ddd = Essai::Item1; 
    std::cout << ddd << std::endl; 

    std::istringstream strm("Item2"); 
    strm >> ddd; 

    std::cout << (int) ddd << std::endl; 
    std::cout << ddd << std::endl; 
} 

हालांकि इस योजना की सीमाओं के बारे में सुनिश्चित नहीं हैं ... टिप्पणियों का स्वागत है!

0
#include <iostream> 
#include <map> 
#define IDMAP(x) (x,#x) 

std::map<int , std::string> enToStr; 
class mapEnumtoString 
{ 
public: 
    mapEnumtoString(){ } 
    mapEnumtoString& operator()(int i,std::string str) 
    { 
     enToStr[i] = str; 
     return *this; 
    } 
public: 
    std::string operator [] (int i) 
    { 
     return enToStr[i]; 
    } 

}; 
mapEnumtoString k; 
mapEnumtoString& init() 
{ 
    return k; 
} 

int main() 
{ 

init() 
    IDMAP(1) 
    IDMAP(2) 
    IDMAP(3) 
    IDMAP(4) 
    IDMAP(5); 
std::cout<<enToStr[1]; 
std::cout<<enToStr[2]; 
std::cout<<enToStr[3]; 
std::cout<<enToStr[4]; 
std::cout<<enToStr[5]; 
} 
+1

कृपया बताएं कि यह जवाब क्यों है। – Gogo

9

मेरे पास मैक्रो का उपयोग करने के लिए एक अविश्वसनीय रूप से सरल है जो इसे पूरी तरह से DRY फैशन में करता है। इसमें विविध मैक्रोज़ और कुछ सरल पार्सिंग जादू शामिल हैं। यहाँ जाता है:

#define AWESOME_MAKE_ENUM(name, ...) enum class name { __VA_ARGS__, __COUNT}; \ 
inline std::ostream& operator<<(std::ostream& os, name value) { \ 
std::string enumName = #name; \ 
std::string str = #__VA_ARGS__; \ 
int len = str.length(); \ 
std::vector<std::string> strings; \ 
std::ostringstream temp; \ 
for(int i = 0; i < len; i ++) { \ 
if(isspace(str[i])) continue; \ 
     else if(str[i] == ',') { \ 
     strings.push_back(temp.str()); \ 
     temp.str(std::string());\ 
     } \ 
     else temp<< str[i]; \ 
} \ 
strings.push_back(temp.str()); \ 
os << enumName << "::" << strings[static_cast<int>(value)]; \ 
return os;} 

अपने कोड में इसके उपयोग के लिए, बस कार्य करें:

AWESOME_MAKE_ENUM(Animal, 
    DOG, 
    CAT, 
    HORSE 
); 
+1

दृढ़ता से टाइप किए गए enum (enum class) का उपयोग करके अच्छा विचार। यहां एक डेमो है: http://cpp.sh/4ife – chappjc

+0

क्या यह बाहरी परिभाषित गणना/प्रतीकों के साथ काम करता है। उदाहरण के लिए, ओएस परिभाषित या लाइब्रेरी परिभाषित प्रतीक संख्याओं में अंतराल के साथ? –

+0

बहुत अच्छा है, लेकिन अगर कक्षा में रखा जाता है तो संकलित नहीं होता है (मैं क्यों नहीं समझ सकता)। – AlwaysLearning

3

इस उत्तर user3360260 @ करने के लिए एक संशोधन है।यह निम्न नई सुविधाओं

  • MyEnum fromString(const string&) समर्थन
  • , VisualStudio 2012
  • enum एक वास्तविक पॉड प्रकार (न सिर्फ स्थिरांक घोषणाओं) है के साथ संकलित ताकि आप इसे एक चर को असाइन कर सकते हैं।
  • अनुमति देने के लिए enum पर "foreach" यात्रा सी ++ "सीमा" सुविधा (वेक्टर के रूप में) जोड़ा

उपयोग:

SMART_ENUM(MyEnum, ONE=1, TWO, THREE, TEN=10, ELEVEN) 
MyEnum foo = MyEnum::TWO; 
cout << MyEnum::toString(foo); // static method 
cout << foo.toString();   // member method 
cout << MyEnum::toString(MyEnum::TWO); 
cout << MyEnum::toString(10); 
MyEnum foo = myEnum::fromString("TWO"); 

// C++11 iteration over all values 
for(auto x : MyEnum::allValues()) 
{ 
    cout << x.toString() << endl; 
} 

कोड यह

#define SMART_ENUM(EnumName, ...)         \ 
class EnumName              \ 
{                 \ 
public:                \ 
    EnumName() : value(0) {}          \ 
    EnumName(int x) : value(x) {}         \ 
public:                \ 
    enum {__VA_ARGS__};            \ 
private:               \ 
    static void initMap(std::map<int, std::string>& tmp)      \ 
    {                \ 
     using namespace std;          \ 
                    \ 
     int val = 0;            \ 
     string buf_1, buf_2, str = #__VA_ARGS__;     \ 
     replace(str.begin(), str.end(), '=', ' ');     \ 
     stringstream stream(str);         \ 
     vector<string> strings;          \ 
     while (getline(stream, buf_1, ','))       \ 
      strings.push_back(buf_1);        \ 
     for(vector<string>::iterator it = strings.begin();   \ 
               it != strings.end(); \ 
               ++it)    \ 
     {               \ 
      buf_1.clear(); buf_2.clear();       \ 
      stringstream localStream(*it);       \ 
      localStream>> buf_1 >> buf_2;       \ 
      if(buf_2.size() > 0)         \ 
       val = atoi(buf_2.c_str());       \ 
      tmp[val++] = buf_1;          \ 
     }               \ 
    }                \ 
    int value;              \ 
public:                \ 
    operator int() const { return value; }       \ 
    std::string toString(void) const {        \ 
      return toString(value);         \ 
    }                \ 
    static std::string toString(int aInt)       \ 
    {                \ 
     return nameMap()[aInt];          \ 
    }                \ 
    static EnumName fromString(const std::string& s)    \ 
    {                \ 
     auto it = find_if(nameMap().begin(), nameMap().end(), [s](const std::pair<int,std::string>& p) { \ 
      return p.second == s;         \ 
     });               \ 
     if (it == nameMap().end()) {        \ 
     /*value not found*/           \ 
      throw EnumName::Exception();       \ 
     } else {             \ 
      return EnumName(it->first);        \ 
     }               \ 
    }                \ 
    class Exception : public std::exception {};      \ 
    static std::map<int,std::string>& nameMap() {     \ 
     static std::map<int,std::string> nameMap0;     \ 
     if (nameMap0.size() ==0) initMap(nameMap0);     \ 
     return nameMap0;            \ 
    }                \ 
    static std::vector<EnumName> allValues() {      \ 
     std::vector<EnumName> x{ __VA_ARGS__ };      \ 
     return x;              \ 
    }                \ 
    bool operator<(const EnumName a) const { return (int)*this < (int)a; } \ 
};   

ध्यान दें कि रूपांतरण करने के लिए स्ट्रिंग एक तेज़ लुकअप है, जबकि स्ट्रिंग से रूपांतरण एक धीमी रैखिक खोज है। लेकिन स्ट्रिंग्स वैसे भी महंगी हैं (और संबंधित फाइल आईओ), मुझे अनुकूलित करने या एक बिटमैप का उपयोग करने की आवश्यकता महसूस नहीं हुई।

+0

आप और उपयोगकर्ता 3360260 का एक अच्छा समाधान है। इसके बजाए एक मल्टीमैप क्यों नहीं है? – Vincent

4

यह सी ++ 11

#include <map> 
enum MyEnum { AA, BB, CC, DD }; 

static std::map< MyEnum, const char * > info = { 
    {AA, "This is an apple"}, 
    {BB, "This is a book"}, 
    {CC, "This is a coffee"}, 
    {DD, "This is a door"} 
}; 

void main() 
{ 
    std::cout << info[AA] << endl 
       << info[BB] << endl 
       << info[CC] << endl 
       << info[DD] << endl; 
} 
+0

यह ओपी के प्रश्न का उत्तर नहीं देता है: वह एक स्ट्रिंग के रूप में enum के सदस्य के नाम को वापस करने के लिए ** स्वचालित रूप से ** एक फ़ंक्शन उत्पन्न करने का तरीका ढूंढ रहा था। – Spooky

+0

धन्यवाद सर्ज !!! – Hans

2

यहाँ एक एक फ़ाइल समाधान किया जा सकता है (सुरुचिपूर्ण उत्तर के आधार पर @Marcin द्वारा:

#include <iostream> 

#define ENUM_TXT \ 
X(Red) \ 
X(Green) \ 
X(Blue) \ 
X(Cyan) \ 
X(Yellow) \ 
X(Magenta) \ 

enum Colours { 
# define X(a) a, 
ENUM_TXT 
# undef X 
    ColoursCount 
}; 

char const* const colours_str[] = { 
# define X(a) #a, 
ENUM_TXT 
# undef X 
    0 
}; 

std::ostream& operator<<(std::ostream& os, enum Colours c) 
{ 
    if (c >= ColoursCount || c < 0) return os << "???"; 
    return os << colours_str[c] << std::endl; 
} 

int main() 
{ 
    std::cout << Red << Blue << Green << Cyan << Yellow << Magenta << std::endl; 
} 
2

यह बूस्ट के साथ अपने समाधान था:

#include <boost/preprocessor.hpp> 

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

#define X_ENUM_STR_TOENUM_IF(r, data, elem)          \ 
    else if(data == BOOST_PP_STRINGIZE(elem)) return elem; 

#define STR_ENUM(name, enumerators)            \ 
    enum name {                 \ 
     BOOST_PP_SEQ_ENUM(enumerators)           \ 
    };                   \ 
                       \ 
    inline const QString enumToStr(name v)          \ 
    {                   \ 
     switch (v)                \ 
     {                  \ 
      BOOST_PP_SEQ_FOR_EACH(            \ 
       X_STR_ENUM_TOSTRING_CASE,          \ 
       name,               \ 
       enumerators              \ 
      )                 \ 
                       \ 
      default:               \ 
       return "[Unknown " BOOST_PP_STRINGIZE(name) "]";    \ 
     }                  \ 
    }                   \ 
                       \ 
    template <typename T>              \ 
    inline const T strToEnum(QString v);          \ 
                       \ 
    template <>                 \ 
    inline const name strToEnum(QString v)          \ 
    {                   \ 
     if(v=="")                \ 
      throw std::runtime_error("Empty enum value");      \ 
                       \ 
     BOOST_PP_SEQ_FOR_EACH(             \ 
      X_ENUM_STR_TOENUM_IF,            \ 
      v,                 \ 
      enumerators               \ 
     )                  \ 
                       \ 
     else                 \ 
      throw std::runtime_error(           \ 
         QString("[Unknown value %1 for enum %2]")    \ 
          .arg(v)            \ 
          .arg(BOOST_PP_STRINGIZE(name))      \ 
           .toStdString().c_str());      \ 
    } 

enum बनाने के लिए, की घोषणा:

STR_ENUM 
(
    SERVICE_RELOAD, 
     (reload_log) 
     (reload_settings) 
     (reload_qxml_server) 
) 

रूपांतरण के लिए:

SERVICE_RELOAD serviceReloadEnum = strToEnum<SERVICE_RELOAD>("reload_log"); 
QString serviceReloadStr = enumToStr(reload_log); 
0

इस पोस्ट की जांच:

Class implementation of C++ Enums

यह C++ enum के वर्ग कार्यान्वयन में शामिल है।

+0

पोस्ट अब मौजूद नहीं है। – AlwaysLearning

+0

@ हमेशा से सीखना मैंने लिंक तय कर दिया है। –

0

अगर कोई इसे उपयोगी पाता है तो मैं इसे पोस्ट करना चाहता हूं।

मेरे मामले में, मुझे केवल ToString() और FromString() एक एकल C++ 11 enum के लिए एक .hpp फ़ाइल से फ़ंक्शन उत्पन्न करने की आवश्यकता है।

मैंने एक पायथन स्क्रिप्ट लिखी है जो एनम आइटम युक्त हेडर फ़ाइल को पार करती है और कार्यों को नई .cpp फ़ाइल में उत्पन्न करती है।

आप इस स्क्रिप्ट को CMakeLists.txt में execute_process, या विजुअल स्टूडियो में प्री-बिल्ड ईवेंट के रूप में जोड़ सकते हैं। .cpp फ़ाइल स्वचालित रूप से जेनरेट की जाएगी, जब भी कोई नया enum आइटम जोड़ा जाता है, इसे मैन्युअल रूप से अपडेट करने की आवश्यकता के बिना।

gener_enum_strings।py

# This script is used to generate strings from C++ enums 

import re 
import sys 
import os 

fileName = sys.argv[1] 
enumName = os.path.basename(os.path.splitext(fileName)[0]) 

with open(fileName, 'r') as f: 
    content = f.read().replace('\n', '') 

searchResult = re.search('enum(.*)\{(.*?)\};', content) 
tokens = searchResult.group(2) 
tokens = tokens.split(',') 
tokens = map(str.strip, tokens) 
tokens = map(lambda token: re.search('([a-zA-Z0-9_]*)', token).group(1), tokens) 

textOut = '' 
textOut += '\n#include "' + enumName + '.hpp"\n\n' 
textOut += 'namespace myns\n' 
textOut += '{\n' 
textOut += ' std::string ToString(ErrorCode errorCode)\n' 
textOut += ' {\n' 
textOut += '  switch (errorCode)\n' 
textOut += '  {\n' 

for token in tokens: 
    textOut += '  case ' + enumName + '::' + token + ':\n' 
    textOut += '   return "' + token + '";\n' 

textOut += '  default:\n' 
textOut += '   return "Last";\n' 
textOut += '  }\n' 
textOut += ' }\n' 
textOut += '\n' 
textOut += ' ' + enumName + ' FromString(const std::string &errorCode)\n' 
textOut += ' {\n' 
textOut += '  if ("' + tokens[0] + '" == errorCode)\n' 
textOut += '  {\n' 
textOut += '   return ' + enumName + '::' + tokens[0] + ';\n' 
textOut += '  }\n' 

for token in tokens[1:]: 
    textOut += '  else if("' + token + '" == errorCode)\n' 
    textOut += '  {\n' 
    textOut += '   return ' + enumName + '::' + token + ';\n' 
    textOut += '  }\n' 

textOut += '\n' 
textOut += '  return ' + enumName + '::Last;\n' 
textOut += ' }\n' 
textOut += '}\n' 

fileOut = open(enumName + '.cpp', 'w') 
fileOut.write(textOut) 

उदाहरण:

ErrorCode.hpp

#pragma once 

#include <string> 
#include <cstdint> 

namespace myns 
{ 
    enum class ErrorCode : uint32_t 
    { 
     OK = 0, 
     OutOfSpace, 
     ConnectionFailure, 
     InvalidJson, 
     DatabaseFailure, 
     HttpError, 
     FileSystemError, 
     FailedToEncrypt, 
     FailedToDecrypt, 
     EndOfFile, 
     FailedToOpenFileForRead, 
     FailedToOpenFileForWrite, 
     FailedToLaunchProcess, 

     Last 
    }; 

    std::string ToString(ErrorCode errorCode); 
    ErrorCode FromString(const std::string &errorCode); 
} 

भागो python generate_enum_strings.py ErrorCode.hpp

परिणाम:

ErrorCode.cpp

#include "ErrorCode.hpp" 

namespace myns 
{ 
    std::string ToString(ErrorCode errorCode) 
    { 
     switch (errorCode) 
     { 
     case ErrorCode::OK: 
      return "OK"; 
     case ErrorCode::OutOfSpace: 
      return "OutOfSpace"; 
     case ErrorCode::ConnectionFailure: 
      return "ConnectionFailure"; 
     case ErrorCode::InvalidJson: 
      return "InvalidJson"; 
     case ErrorCode::DatabaseFailure: 
      return "DatabaseFailure"; 
     case ErrorCode::HttpError: 
      return "HttpError"; 
     case ErrorCode::FileSystemError: 
      return "FileSystemError"; 
     case ErrorCode::FailedToEncrypt: 
      return "FailedToEncrypt"; 
     case ErrorCode::FailedToDecrypt: 
      return "FailedToDecrypt"; 
     case ErrorCode::EndOfFile: 
      return "EndOfFile"; 
     case ErrorCode::FailedToOpenFileForRead: 
      return "FailedToOpenFileForRead"; 
     case ErrorCode::FailedToOpenFileForWrite: 
      return "FailedToOpenFileForWrite"; 
     case ErrorCode::FailedToLaunchProcess: 
      return "FailedToLaunchProcess"; 
     case ErrorCode::Last: 
      return "Last"; 
     default: 
      return "Last"; 
     } 
    } 

    ErrorCode FromString(const std::string &errorCode) 
    { 
     if ("OK" == errorCode) 
     { 
      return ErrorCode::OK; 
     } 
     else if("OutOfSpace" == errorCode) 
     { 
      return ErrorCode::OutOfSpace; 
     } 
     else if("ConnectionFailure" == errorCode) 
     { 
      return ErrorCode::ConnectionFailure; 
     } 
     else if("InvalidJson" == errorCode) 
     { 
      return ErrorCode::InvalidJson; 
     } 
     else if("DatabaseFailure" == errorCode) 
     { 
      return ErrorCode::DatabaseFailure; 
     } 
     else if("HttpError" == errorCode) 
     { 
      return ErrorCode::HttpError; 
     } 
     else if("FileSystemError" == errorCode) 
     { 
      return ErrorCode::FileSystemError; 
     } 
     else if("FailedToEncrypt" == errorCode) 
     { 
      return ErrorCode::FailedToEncrypt; 
     } 
     else if("FailedToDecrypt" == errorCode) 
     { 
      return ErrorCode::FailedToDecrypt; 
     } 
     else if("EndOfFile" == errorCode) 
     { 
      return ErrorCode::EndOfFile; 
     } 
     else if("FailedToOpenFileForRead" == errorCode) 
     { 
      return ErrorCode::FailedToOpenFileForRead; 
     } 
     else if("FailedToOpenFileForWrite" == errorCode) 
     { 
      return ErrorCode::FailedToOpenFileForWrite; 
     } 
     else if("FailedToLaunchProcess" == errorCode) 
     { 
      return ErrorCode::FailedToLaunchProcess; 
     } 
     else if("Last" == errorCode) 
     { 
      return ErrorCode::Last; 
     } 

     return ErrorCode::Last; 
    } 
} 
+0

यहां एक ऑनलाइन जनरेटर है: http://th-thielemann.de/tools/cpp-enum-to-string.html –

0

ठीक है, फिर भी एक और विकल्प। एक सामान्य उपयोग केस है जहां आपको HTTP क्रियाओं के साथ-साथ स्ट्रिंग संस्करण मानों का उपयोग करने के लिए निरंतर आवश्यकता होती है।

उदाहरण:

int main() { 

    VERB a = VERB::GET; 
    VERB b = VERB::GET; 
    VERB c = VERB::POST; 
    VERB d = VERB::PUT; 
    VERB e = VERB::DELETE; 


    std::cout << a.toString() << std::endl; 

    std::cout << a << std::endl; 

    if (a == VERB::GET) { 
    std::cout << "yes" << std::endl; 
    } 

    if (a == b) { 
    std::cout << "yes" << std::endl; 
    } 

    if (a != c) { 
    std::cout << "no" << std::endl; 
    } 

} 

VERB वर्ग:

// ----------------------------------------------------------- 
// ----------------------------------------------------------- 
class VERB { 

private: 

    // private constants 
    enum Verb {GET_=0, POST_, PUT_, DELETE_}; 

    // private string values 
    static const std::string theStrings[]; 

    // private value 
    const Verb value; 
    const std::string text; 

    // private constructor 
    VERB (Verb v) : 
    value(v), text (theStrings[v]) 
    { 
    // std::cout << " constructor \n"; 
    } 

public: 

    operator const char *() const { return text.c_str(); } 

    operator const std::string() const { return text; } 

    const std::string toString() const { return text; } 

    bool operator == (const VERB & other) const { return (*this).value == other.value; } 

    bool operator != (const VERB & other) const { return ! ((*this) == other); } 

    // --- 

    static const VERB GET; 
    static const VERB POST; 
    static const VERB PUT; 
    static const VERB DELETE; 

}; 

const std::string VERB::theStrings[] = {"GET", "POST", "PUT", "DELETE"}; 

const VERB VERB::GET = VERB (VERB::Verb::GET_); 
const VERB VERB::POST = VERB (VERB::Verb::POST_); 
const VERB VERB::PUT = VERB (VERB::Verb::PUT_); 
const VERB VERB::DELETE = VERB (VERB::Verb::DELETE_); 
// end of file 
0

यौगिक त्रिगुट बयानों का उपयोग करते हुए कुछ तत्व (एक-लाइनर) के साथ enums के लिए कुछ हद तक सुरुचिपूर्ण हो सकता है। अभिव्यक्ति केवल तत्वों की संख्या के साथ लंबाई में लगभग रैखिक रूप से बढ़ती है।

यहाँ एक अच्छा उपयोग मामला है:

enum log_level {INFO, WARNING, ERROR}; 
... 
void logger::write(const std::string log, const log_level l) { 
    ... 
    std::string s = (l == INFO) ? "INFO" : 
        (l == WARNING) ? "WARNING" : 
        (l == ERROR) ? "ERROR" : "UNKNOWN"; 
    ... 
} 
... 
बेशक

, यह सिर्फ एक और स्विच/अगर बयान ब्लॉक है, लेकिन यह एक ही पंक्ति बयान है। और terseness बनाम सादगी के मामले के रूप में, यह बीच में कहीं मिलती है। निरंतर अभिव्यक्ति के रूप में, इसे आसानी से एक इनलाइन फ़ंक्शन में भी बनाया जा सकता है।

संबंधित मुद्दे

 संबंधित मुद्दे