क्या C ++ एनम को स्ट्रिंग में बदलने का एक सरल तरीका है?


123

मान लीजिए कि हमारे पास कुछ नामांकित व्यक्ति हैं:

enum MyEnum {
      FOO,
      BAR = 0x50
};

मैंने जिस स्क्रिप्ट के लिए गुगली की, वह एक स्क्रिप्ट (कोई भी भाषा) है, जो मेरे प्रोजेक्ट के सभी हेडर को स्कैन करती है और एनम के साथ एक फंक्शन के साथ हेडर बनाती है।

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

गेटचा वास्तव में टाइप किए गए एनम के साथ है, और अनाम सी शैली एनम हैं। क्या कोई इसके लिए कुछ जानता है?

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


मैक्रो आधारित कारखाने के बारे में जवाब stackoverflow.com/questions/147267/… में चले गए - सवाल अपडेट होने के बाद, यह अब यहाँ प्रासंगिक नहीं है।
सुमा

जवाबों:


48

आप 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>

आप किसी भी भाषा का उपयोग कर सकते हैं जिसे आप Enumeration और EnumValue टैग से बाहर निकालना चाहते हैं और अपना वांछित कोड उत्पन्न करते हैं।


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

6
+1, GCCXML बहुत अच्छा लग रहा है! (हालांकि मैं लगभग -1ed के रूप में मैं शुरू में यह एक सुझाव के रूप में यह गलत समझा एक्सएमएन सिंटैक्स का उपयोग करने के लिए अपने एनम को सांकेतिक शब्दों में बदलना - एक समाधान जो अतिरंजना का पुनर्मिलन!)
j_random_hacker

1
किसी भी परिवर्तन आप अजगर स्क्रिप्ट पोस्ट कर सकते हैं?
फिलिप्पेइवी

74

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

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

colours.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
निफ्टी, हालांकि मुझे अतिरिक्त फाइल पसंद नहीं है
रॉनी ब्रेंडल

2
बस सुनिश्चित करें कि आपकी निर्माण प्रक्रिया में हर फ़ाइल शामिल करने से पहले #pragma (एक बार) पूर्व
निर्धारित नहीं है

24
मुझे "सर्वश्रेष्ठ" समाधान के बारे में निश्चित नहीं है!
ऑर्बिट

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

2
@ ikku100 आप गलत हैं #define X(a, b) #b। यह केवल तभी आवश्यक है जब परिभाषा X(Red, red)उत्तर में दिखाई गई परिभाषा के बजाय इस तरह दिखती है ,X(Red, "red")
Learnvst

43

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

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

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

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

मुझे इस सरल समाधान के लिए धन्यवाद देना चाहिए :-) - मैंने इसे थोड़ा संशोधित किया, हालांकि, MetaSyntacticVariableNames[]एक क्लास डिक्लेरेशन का हिस्सा होने के लिए, एक विधि बनाकरstatic const char* getNameByEnum(MetaSyntacticVariable e) { /*code to return the static string*/ }
डेकर डीके

शानदार जवाब! मैंने इसे MAKE_ENUM और MAKE_STRINGS को एक ही मैक्रो में समूहीकृत करके और सरल कर दिया, जिससे पूरी प्रक्रिया और भी सरल हो गई। मैंने उस कोड के साथ इस धागे में एक उत्तर जोड़ा, अगर किसी को दिलचस्पी है।
फ्रेंकोइस बर्ट्रेंड

35

मैं जो कुछ भी करता हूं, वह उसी क्रम और स्थिति में नाम के साथ सी सरणी बनाता है जैसे कि एनम मान।

जैसे।

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

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

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

आप स्ट्रिंगिंग ऑपरेटर (अपने प्रीप्रोसेसर संदर्भ में # देखें) के साथ थोड़ा प्रयोग कर सकते हैं जो कुछ परिस्थितियों में आपको चाहिए।

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

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


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

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

11

मेरे पास मैक्रो का उपयोग करने के लिए एक अविश्वसनीय रूप से सरल है जो पूरी तरह से 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
एक जोरदार टाइप्ड एनम (एनम वर्ग) का उपयोग करके अच्छा विचार। यहाँ एक डेमो है: cpp.sh/4ife
chappjc

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

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

मुझे यह VS2015 में संकलित करने के लिए नहीं मिला। मुझे एक चेतावनी और एक त्रुटि मिलती है: चेतावनी: बहु-पंक्ति टिप्पणी [-Wcomment] #define MAKE_ENUM (नाम, ...) enum वर्ग का नाम { VA_ARGS , __COUNT} त्रुटि: stray '#' प्रोग्राम में std *: string enumName = #name
क्रेग.फाइड

8

क्यूटी (मेटा ऑब्जेक्ट कंपाइलर के लिए धन्यवाद) को खींचने में सक्षम है:

QNetworkReply::NetworkError error;

error = fetchStuff();

if (error != QNetworkReply::NoError) {

    QString errorValue;

    QMetaObject meta = QNetworkReply::staticMetaObject;

    for (int i=0; i < meta.enumeratorCount(); ++i) {

        QMetaEnum m = meta.enumerator(i);

        if (m.name() == QLatin1String("NetworkError")) {

            errorValue = QLatin1String(m.valueToKey(error));

            break;

        }

    }

    QMessageBox box(QMessageBox::Information, "Failed to fetch",

                "Fetching stuff failed with error '%1`").arg(errorValue),

                QMessageBox::Ok);

    box.exec();

    return 1;

}

Qt में प्रत्येक वर्ग जिसमें Q_OBJECT मैक्रो होता है, उसके पास QMetaObject प्रकार का "स्टैटिकमैटोऑब्जेक्ट" स्थिर सदस्य होगा। फिर आप सभी प्रकार की शांत चीजें पा सकते हैं जैसे गुण, संकेत, स्लॉट और वास्तव में एनम।

स्रोत


7

यह C ++ 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;
}

1
यह ओपी के सवाल का जवाब नहीं देता है: वह एक एनुम के सदस्य के नाम को एक स्ट्रिंग के रूप में वापस करने के लिए स्वचालित रूप से एक फ़ंक्शन उत्पन्न करने के लिए एक रास्ता तलाश रहा था ।
डरावना

7

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

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

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

अच्छा समाधान। लेकिन मेरे लिए switch and caseयह पसंद है क्योंकि यह सरल और समझने में आसान है।
देकिंग में

6
#define stringify( name ) # name

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

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

इस विधि पर आगे की चर्चा

नए लोगों के लिए प्रीप्रोसेसर निर्देश चाल


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

5

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

फ़ाइल myenummap.h में:

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

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

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

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

1
यह पूरी तरह से कानूनी है। मुझे हर व़क्त यह करना है।
जोनाथन ग्रेहल

अच्छा समाधान। यह c ++ है इसलिए stl मैप का उपयोग करना ठीक है।
एडम ब्रून

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
मुझे आपका API पसंद है, लेकिन दुर्भाग्य से, आपका SmartEnum वास्तव में एक एनम "टाइप" नहीं बनाता है। तुम नहीं कर सकते MyEnum x = MyEnum::TWO;। मैंने इसका समर्थन करने के लिए आपकी कक्षा का अपना संपादन पोस्ट किया है।
निशान लता

4

सुमा का स्थूल समाधान अच्छा है। हालांकि आपको दो अलग-अलग मैक्रो की आवश्यकता नहीं है। C ++ wil में खुशी से एक हैडर दो बार शामिल होता है। बस शामिल गार्ड को छोड़ दें।

तो तुम एक foobar.h सिर्फ परिभाषित करना होगा

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

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

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

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

आप enumfactory.h को कई बार शामिल कर सकते हैं, वह भी, जब तक आप ENUMFACTORY_ARGUMENT के लिए अलग # परिभाषित में पास होते हैं


लगता है कि सुमा ने उत्तर को यहां स्थानांतरित कर दिया । आप अपने उत्तर में लिंक को शामिल करना चाह सकते हैं। मुझे केवल संयोग से टिप्पणी मिली और विटाम सुमा का जवाब यह है कि यह बेकार है
idclev 463035818

3

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

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

#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 परिभाषा और रूपांतरण फ़ंक्शन हमेशा सिंक में रहेंगे। हालांकि, मैं दोहराता हूं, यह बदसूरत है :)


3

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


3

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

  • MyEnum fromString(const string&) सहयोग
  • VisualStudio 2012 के साथ संकलित
  • enum एक वास्तविक POD प्रकार है (न कि केवल अघोषित घोषणाएँ), इसलिए आप इसे एक चर में निर्दिष्ट कर सकते हैं।
  • जोड़ा सी ++ "रेंज" सुविधा (वेक्टर के रूप में) एनम पर "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; } \
};         

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


आपके और user3360260 का अच्छा समाधान है। इसके बजाय मल्टीपैप क्यों नहीं है?
विंसेंट

3

यहाँ एक फ़ाइल समाधान (@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

मैं इसे अलग-अलग साइड-बाय-साइड एनम रैपर क्लासेस के साथ करता हूं जो मैक्रोज़ के साथ उत्पन्न होते हैं। कई फायदे हैं:

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

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

यहाँ मेरे कोडबेस से एक एनम का एक उदाहरण है, सभी फ्रेमवर्क कोड को मैन्स और टेम्प्लेट को लागू करता है, लेकिन आप यह विचार प्राप्त कर सकते हैं:

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 (...) का उपयोग कर सकते हैं।

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


2

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


2

BOOST के साथ यह मेरा समाधान था:

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

एनम बनाने के लिए, घोषित करें:

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

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

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

2

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

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

मैंने एक पाइथन स्क्रिप्ट लिखी है, जो एनम आइटम वाली हेडर फाइल को पार्स करती है और एक नए में फंक्शन्स को जनरेट करती है .cpp फाइल ।

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

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

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

1
यहाँ एक ऑनलाइन जनरेटर है: th-thielemann.de/tools/cpp-enum-to-string.html
Th। थिलेमन

2

जैस्पर बेकर्स के शानदार उत्तर के उपयोग की और भी सरलता को जोड़ना :

एक बार सेट करें:

#define MAKE_ENUM(VAR) VAR,
#define MAKE_STRINGS(VAR) #VAR,
#define MAKE_ENUM_AND_STRINGS(source, enumName, enumStringName) \
    enum enumName { \
    source(MAKE_ENUM) \
    };\
const char* const enumStringName[] = { \
    source(MAKE_STRINGS) \
    };

फिर, उपयोग के लिए:

#define SOME_ENUM(DO) \
    DO(Foo) \
    DO(Bar) \
    DO(Baz)
...
MAKE_ENUM_AND_STRINGS(SOME_ENUM, someEnum, someEnumNames)

2

आप पैंडर की तरह एक प्रतिबिंब पुस्तकालय का उपयोग कर सकते हैं । आप एनमों को पंजीकृत करते हैं और फिर आप उन्हें एपीआई के साथ आगे और पीछे परिवर्तित कर सकते हैं।

enum class MyEnum
{
    Zero = 0,
    One  = 1,
    Two  = 2
};

ponder::Enum::declare<MyEnum>()
    .value("Zero", MyEnum::Zero)
    .value("One",  MyEnum::One)
    .value("Two",  MyEnum::Two);

ponder::EnumObject zero(MyEnum::Zero);

zero.name(); // -> "Zero"

1

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

जब मुझे इसकी आवश्यकता होती है, तो मैं आमतौर पर:

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

1

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

#! /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))
    }
  }
}

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

मान लें कि आपके पास एक हेडर टोटो / आह है, जिसमें Enums MyEnum और MyEnum2 की परिभाषाएँ हैं। स्क्रिप्ट का निर्माण होगा:

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

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

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

0

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

समस्या यह है, एक बार एक सी प्रोग्राम संकलित किया जाता है, तो एनम के द्विआधारी मूल्य का उपयोग किया जाता है, और नाम चला गया है।


0

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

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

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

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


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

0

ऐसा नहीं है कि कुछ समय पहले मैंने QComboBox में एनमों को ठीक से प्रदर्शित करने के लिए कुछ तरकीबें कीं और अपने बयान के अनुसार एनम और स्ट्रिंग अभ्यावेदन की परिभाषा दी

#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)))))
*/

अब आप enumeration::enum_singleton<your_enum>::instance()एनम को स्ट्रिंग्स में बदलने में सक्षम हो गए हैं। यदि आप के kv_storage_tसाथ प्रतिस्थापित करते हैं boost::bimap, तो आप भी पिछड़े रूपांतरण करने में सक्षम होंगे। कनवर्टर के लिए सामान्य आधार वर्ग को Qt ऑब्जेक्ट में संग्रहीत करने के लिए पेश किया गया था, क्योंकि Qt ऑब्जेक्ट्स टेम्पलेट नहीं हो सकते

पिछली उपस्थिति


0

वैरिएंट के रूप में, साधारण लिब का उपयोग करें> 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 FORM f = ...
const std::string& str = EnumString< FORM >::From( f );

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

assert( EnumString< FORM >::To( f, str ) );

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

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