স্ট্রিংয়ে কীভাবে সি ++ এনামগুলিকে সহজে মানচিত্র করা যায়


119

আমি ব্যবহার করছি এমন কয়েকটি লাইব্রেরির শিরোনাম ফাইলগুলিতে আমার গুচ্ছ এনাম ধরণের রয়েছে এবং আমি এনাম মানগুলি ব্যবহারকারীর স্ট্রিংয়ে রূপান্তর করতে চাই - এবং তদ্বিপরীত।

আরটিটিআই আমার পক্ষে এটি করবে না, কারণ 'ব্যবহারকারীর স্ট্রিংস' গণনার চেয়ে কিছুটা বেশি পঠনযোগ্য হওয়া দরকার।

একটি নিষ্ঠুর বলের সমাধান এর মত কাজগুলির একটি গুচ্ছ হতে পারে, তবে আমি মনে করি এটি কিছুটা সি-এর মতো।

enum MyEnum {VAL1, VAL2,VAL3};

String getStringFromEnum(MyEnum e)
{
  switch e
  {
  case VAL1: return "Value 1";
  case VAL2: return "Value 2";
  case VAL1: return "Value 3";
  default: throw Exception("Bad MyEnum");
  }
}

আমার এক অন্ত্র অনুভূতি রয়েছে যে টেমপ্লেটগুলি ব্যবহার করে একটি দুর্দান্ত সমাধান রয়েছে, তবে আমি এখনও আমার মাথাটি পুরোপুরি পেতে পারি না।

আপডেট: পরামর্শের জন্য ধন্যবাদ - আমার স্পষ্ট করে দেওয়া উচিত ছিল যে এনামগুলি তৃতীয় পক্ষের লাইব্রেরির শিরোনামে সংজ্ঞায়িত করা হয়েছে, সুতরাং আমি তাদের সংজ্ঞাটি পরিবর্তন করতে চাই না।

আমার এখন অন্ত্র অনুভূতি হ'ল টেমপ্লেটগুলি এড়ানো এবং এরকম কিছু করা:

char * MyGetValue(int v, char *tmp); // implementation is trivial

#define ENUM_MAP(type, strings) char * getStringValue(const type &T) \
 { \
 return MyGetValue((int)T, strings); \
 }

; enum eee {AA,BB,CC}; - exists in library header file 
; enum fff {DD,GG,HH}; 

ENUM_MAP(eee,"AA|BB|CC")
ENUM_MAP(fff,"DD|GG|HH")

// To use...

    eee e;
    fff f;
    std::cout<< getStringValue(e);
    std::cout<< getStringValue(f);

উত্তর:


60

আপনি যদি এনামদের নিজের নামগুলি স্ট্রিং হিসাবে চান তবে এই পোস্টটি দেখুন । অন্যথায়, একটি ভাল std::map<MyEnum, char const*>কাজ করবে। (মানচিত্রে আপনার স্ট্রিং লিটারেলগুলি স্টাডি :: স্ট্রিংগুলিতে অনুলিপি করার কোনও অর্থ নেই)

অতিরিক্ত সিনট্যাকটিক চিনির জন্য, মানচিত্র_ইনিট ক্লাস কীভাবে লিখবেন তা এখানে's লক্ষ্য অনুমতি দেওয়া হয়

std::map<MyEnum, const char*> MyMap;
map_init(MyMap)
    (eValue1, "A")
    (eValue2, "B")
    (eValue3, "C")
;

ফাংশনটি template <typename T> map_init(T&)a map_init_helper<T>map_init_helper<T>একটি টি ও সঞ্চয় করে এবং তুচ্ছ সংজ্ঞা দেয় map_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)। (রিটার্নিং *thisথেকে operator()এর chaining পারবেন operator(), মত operator<<উপর std::ostreamগুলি)

template<typename T> struct map_init_helper
{
    T& data;
    map_init_helper(T& d) : data(d) {}
    map_init_helper& operator() (typename T::key_type const& key, typename T::mapped_type const& value)
    {
        data[key] = value;
        return *this;
    }
};

template<typename T> map_init_helper<T> map_init(T& item)
{
    return map_init_helper<T>(item);
}

যেহেতু ফাংশন এবং সহায়ক শ্রেণিভিত্তিক তৈরি হয়েছে, আপনি এগুলি যে কোনও মানচিত্র, বা মানচিত্রের মতো কাঠামোর জন্য ব্যবহার করতে পারেন। অর্থাৎ এটিতে এন্ট্রিও যুক্ত করতে পারেstd::unordered_map

আপনি যদি এই সহায়কগুলি লিখতে পছন্দ করেন না তবে বুস্ট :: অ্যাসাইন বাক্সের বাইরে একই কার্যকারিতা সরবরাহ করে।


আপনি অন্য একটি প্রশ্ন উল্লেখ করা ঠিক। লোকেরা পোস্ট করার আগে "সম্পর্কিত প্রশ্নগুলি" দেখে নেওয়া উচিত ...
xtofl

2
@xtofl: আমি যখন প্রশ্ন পোস্ট করি তখন তালিকাভুক্ত সম্পর্কিত প্রশ্নের সাথে এখানে প্রদর্শিত "সম্পর্কিত প্রশ্নগুলি" সম্পূর্ণ আলাদা!
রডি

@ এসএমএল্টারস, একটি স্ট্যান্ড :: ম্যাপটি বাস্তবায়ন পরিচালনা করার একটি কার্যকর উপায়, তবে আমি বয়লারপ্লেট কোড হ্রাস করার কিছু উপায় খুঁজছি যা প্রয়োজন হতে পারে।
রডি 12 ই

@ এসএমএলটারস, অপারেটরের জন্য একাধিক যুক্তি গ্রহণ করতে সক্ষম হবেন []] তবে দুঃখের বিষয়, কেউ তা করতে পারে না। x [ক, খ] এক্স [খ] এর মূল্যায়ন করুন। (a, b) এক্সপ্রেশনটি কমা অপারেটরের ব্যবহার করে। সুতরাং এটি আপনার কোডে ["এ"] ["বি"] ["সি"] এর সমতুল্য। আপনি এটি বলার জন্য এটি পরিবর্তন করতে পারেন [eValue1] ["এ"] [ইভালু ..
জোহানেস স্কাউব - লিটব

ফাংশন কল অপারেটরটিও একজন ভাল প্রার্থী হবে: মানচিত্র_ইনিট (মাইম্যাপ) (ইভালিউ 1, "এ") (ইভালিউ 2, "বি") .... তারপরে এটি উত্সাহের সমতুল্য: নির্ধারিত: সন্নিবেশ (মাইম্যাপ) (eValue1, "এ") (eValue2, "বি") ... ( boost.org/doc/libs/1_35_0/libs/assign/doc/index.html )
জোহানেস স্কাউব - লিটব

31

MSalters সমাধান ভালো কিন্তু মূলত পুনরায় কার্যকরী boost::assign::map_list_of। আপনার যদি বিকাশ হয় তবে আপনি এটি সরাসরি ব্যবহার করতে পারেন:

#include <boost/assign/list_of.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>

using boost::assign::map_list_of;

enum eee { AA,BB,CC };

const boost::unordered_map<eee,const char*> eeeToString = map_list_of
    (AA, "AA")
    (BB, "BB")
    (CC, "CC");

int main()
{
    std::cout << " enum AA = " << eeeToString.at(AA) << std::endl;
    return 0;
}

EeeToString একটি শ্রেণীর ডেটা সদস্য যেখানে আপনি এটি কীভাবে ব্যবহার করবেন? আমি পেয়েছি "ত্রুটি: ডেটা সদস্য সূচনার অনুমতি নেই"
ব্যবহারকারী

@ ব্যবহারকারী: ক্লাসের ডেটা সদস্যগণ সাধারণত প্রাথমিকের তালিকায় কনস্ট্রাক্টরগুলিতে আরম্ভ হয়।
MSalters

সমস্ত এনামগুলির জন্য এই কাজটি করার কোনও উপায় আছে কি? আমার একাধিক এনাম ঘোষণা রয়েছে এবং মানচিত্রটি কেবল eeeআপনার ক্ষেত্রে টাইপের জন্য কাজ করতে চায় না ।
জাস্টিন লিয়াং

আমি একটি টেমপ্লেট ব্যবহার করার চেষ্টা কিন্তু তারপর উঠে ত্রুটি: error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
জাস্টিন লিয়াং

4
আসলে এই উত্তরটি সি ++ 11 দিয়ে বেশিরভাগই অপ্রচলিত।
অ্যালেস্টার

19

অন্যটি থেকে একটি ফর্ম স্বয়ংক্রিয়ভাবে উত্পন্ন করুন।

উৎস:

enum {
  VALUE1, /* value 1 */
  VALUE2, /* value 2 */
};

তৈরি করা হয়েছে:

const char* enum2str[] = {
  "value 1", /* VALUE1 */
  "value 2", /* VALUE2 */
};

যদি এনাম মানগুলি বড় হয় তবে উত্পন্ন ফর্মটি কন্সট্যান্টিনের পরামর্শ অনুসারে আনর্ডার্ড_ম্যাপ <> বা টেম্পলেট ব্যবহার করতে পারে।

উৎস:

enum State{
  state0 = 0, /* state 0 */
  state1 = 1, /* state 1 */
  state2 = 2, /* state 2 */
  state3 = 4, /* state 3 */

  state16 = 0x10000, /* state 16 */
};

তৈরি করা হয়েছে:

template <State n> struct enum2str { static const char * const value; };
template <State n> const char * const enum2str<n>::value = "error";

template <> struct enum2str<state0> { static const char * const value; };
const char * const enum2str<state0>::value = "state 0";

উদাহরণ:

#include <iostream>

int main()
{
  std::cout << enum2str<state16>::value << std::endl;
  return 0;
}

দ্রুততম সময়ে, এটি @ এসএমএলটারগুলির মতো সহজ নয়।
কেনে

2
পাঠ্য ফাইল থেকে স্ট্রিংয়ের একটি তালিকা পড়তে এবং সংকলনের সময় স্থির চরের সাথে একটি .h ফাইল উত্পন্ন করার জন্য যদি আপনার কাছে পার্ল / অজগর কিছুটা থাকে। = "প্রোগ্রাম লিখতে প্রোগ্রাম লিখুন"
মার্টিন বেকেট

@ এমজিবি: পার্ল / পাইথন কেবলমাত্র কোনও বিকল্পই নয় যে কোনও ভাষার প্রায় কোনও টেম্পলেট ইঞ্জিনই এটি করতে পারে (এক্ষেত্রে কোনও একটি টেমপ্লেট থেকে উভয় ফর্ম তৈরি করে)।
jfs

@jf। হ্যাঁ, গুরুত্বপূর্ণ বিষয়টি ছিল স্বয়ংক্রিয়ভাবে সংকলনের সময় স্থিতিশীল ডেটা টেবিলগুলি তৈরি করা। আমি সম্ভবত কেবল বোবা স্ট্যাটিক অ্যারে তৈরি করতে পছন্দ করব।
মার্টিন Beckett

সংকলন সময়ে রাজ্যটি জানা না থাকলে এই কাজ করবে? আমি নিশ্চিত যে এটি করবে না - তাত্ত্বিকভাবে সংকলকটি এনামের সমস্ত সম্ভাব্য মান সহ এনাম 2 জাস্ট্রাল টেমপ্লেট ইনস্ট্যান্ট করতে হবে, যা আমি নিশ্চিত যে জিসিসি (কমপক্ষে) তা করবে না।
অ্যালাস্টার

11

আমার মনে আছে স্ট্যাক ওভারফ্লোতে অন্যত্র এর উত্তর দেওয়া হয়েছিল। এখানে এটি পুনরাবৃত্তি। মূলত এটি ভ্যারিয়েডিক ম্যাক্রোর উপর ভিত্তি করে একটি সমাধান এবং এটি ব্যবহার করা বেশ সহজ:

#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
);
auto dog = Animal::DOG;
std::cout<<dog;

1
প্রিম সি ++ 11 এ কাজ করার জন্য কেবল এনাম শ্রেণীর ঘোষণাটি এনুমে পরিবর্তন করুন।
দেবদত্ত বসু

1
আপনি ঠিক বলেছেন এটি কাজ করে (স্বয়ংক্রিয়ভাবে কেবল সি ++ 11)। চমৎকার সমাধান! এটি নিখুঁত হবে যদি আপনি কিছু
এনামের

আমার ধারণা আমি এরকম কিছু উত্সাহিত করতে দেখেছি
সের্গেই

10

আমি এক্স-ম্যাক্রো ব্যবহারের মিশ্রণটি সেরা সমাধান এবং নিম্নলিখিত টেম্পলেট ফাংশনগুলি প্রস্তাব করি:

Marcinkoziukmyopenidcom বন্ধ এবং প্রসারিত

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

template <class T> T str2enum( const char* );
template <class T> const char* enum2str( T );

#define STR2ENUM(TYPE,ARRAY) \
template <> \
TYPE str2enum<TYPE>( const char* str ) \
    { \
    for( int i = 0; i < (sizeof(ARRAY)/sizeof(ARRAY[0])); i++ ) \
        if( !strcmp( ARRAY[i], str ) ) \
            return TYPE(i); \
    return TYPE(0); \
    }

#define ENUM2STR(TYPE,ARRAY) \
template <> \
const char* enum2str<TYPE>( TYPE v ) \
    { \
    return ARRAY[v]; \
    }

#define ENUMANDSTR(TYPE,ARRAY)\
    STR2ENUM(TYPE,ARRAY) \
    ENUM2STR(TYPE,ARRAY)

ENUMANDSTR(Colours,colours_str)

colour.def

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

এনাম স্ট্রিং অ্যারে সংজ্ঞা জেনেরিক করার কোনও উপায় আছে কি? (আমি জানি না কীভাবে ম্যাক্রোর ভিতরে কোনও এক্স-ম্যাক্রো পরিচালনা করতে হয় এবং আমি সহজে টেমপ্লেটটি পরিচালনা করি না)
জোনাথন

5

আমি এই সমাধানটি ব্যবহার করি যা আমি নীচে পুনরুত্পাদন করছি:

#define MACROSTR(k) #k

#define X_NUMBERS \
       X(kZero  ) \
       X(kOne   ) \
       X(kTwo   ) \
       X(kThree ) \
       X(kFour  ) \
       X(kMax   )

enum {
#define X(Enum)       Enum,
    X_NUMBERS
#undef X
} kConst;

static char *kConstStr[] = {
#define X(String) MACROSTR(String),
    X_NUMBERS
#undef X
};

int main(void)
{
    int k;
    printf("Hello World!\n\n");

    for (k = 0; k < kMax; k++)
    {
        printf("%s\n", kConstStr[k]);
    }

    return 0;
}

1
এটি বেসিক এক্স ম্যাক্রোস, এবং আমি স্তব্ধ হয়ে গেছি যে এটি এখানে প্রস্তাবনের প্রথম উত্তর! +1
অরবিট

4

আপনি যদি MyEnum ভেরিয়েবলের স্ট্রিং উপস্থাপনা পেতে চান তবে টেমপ্লেটগুলি এটি কাটবে না। টেমপ্লেট সংকলন সময়ে পরিচিত অবিচ্ছেদ্য মানগুলিতে বিশেষীকরণ করা যেতে পারে।

তবে, যদি আপনি এটি চান তবে চেষ্টা করুন:

#include <iostream>

enum MyEnum { VAL1, VAL2 };

template<MyEnum n> struct StrMyEnum {
    static char const* name() { return "Unknown"; }
};

#define STRENUM(val, str) \
  template<> struct StrMyEnum<val> { \
    static char const* name() { return str; }};

STRENUM(VAL1, "Value 1");
STRENUM(VAL2, "Value 2");

int main() {
  std::cout << StrMyEnum<VAL2>::name();
}

এটি ভার্ভোজ, তবে আপনি case VAL1যেমন প্রশ্ন করেছেন তার মতো ত্রুটিগুলি ধরবে - এটির সদৃশ is


আসলে পদ্ধতির নাম () প্রয়োজন হয় না। আমার উত্তর দেখুন।
jfs

3

আমি স্বীকার করতে চাই এই বিষয়টি গবেষণা করার জন্য আমি আরও বেশি সময় ব্যয় করেছি। ভাগ্যক্রমে বন্য মধ্যে দুর্দান্ত মুক্ত উত্স সমাধান আছে।

এগুলি দুটি দুর্দান্ত পন্থা, যদিও যথেষ্ট পরিচিত না হলেও (এখনও),

wise_enum

  • সি ++ 11/14/17 এর জন্য স্বতন্ত্র স্মার্ট এনাম লাইব্রেরি। এটি স্ট্যান্ডার্ড কার্যকারিতার সমস্তটিকে সমর্থন করে যা আপনি সি ++ এর স্মার্ট এনাম শ্রেণীর কাছ থেকে আশা করবেন।
  • সীমাবদ্ধতা: কমপক্ষে সি ++ 11 প্রয়োজন।

ভাল Enums

  • একটি একক শিরোনাম ফাইলে এবং নির্ভরতা ছাড়াই ক্লিন সিনট্যাক্স সহ প্রতিবিম্বিত সংকলন-সময় এনাম লাইব্রেরি।
  • সীমাবদ্ধতা: ম্যাক্রোগুলির উপর ভিত্তি করে কোনও শ্রেণীর অভ্যন্তরে ব্যবহার করা যাবে না।

2

আমি একটি মানচিত্রের মিটার প্রলোভন করব - এবং এটি এনামে এম্বেড করেছি।

m [MyEnum.VAL1] = "মান 1" সহ সেটআপ;

এবং সব সম্পন্ন হয়েছে।


2

অন্যের কাছ থেকে কোডটি ডিবাগিং / বিশ্লেষণের জন্য আমি এই কার্যকারিতাটি বেশ কয়েকবার প্রয়োজন। এর জন্য, আমি একটি পার্ল স্ক্রিপ্ট লিখেছি যা বেশ কয়েকটি ওভারলোড toStringপদ্ধতি সহ একটি শ্রেণি তৈরি করে। প্রতিটি toStringপদ্ধতি Enumআর্গুমেন্ট হিসাবে গ্রহণ করে এবং ফেরত দেয় const char*

অবশ্যই, স্ক্রিপ্টটি এনামগুলিতে নিজের জন্য সি ++ পার্স করে না, তবে প্রতীক টেবিল তৈরির জন্য ctags ব্যবহার করে।

পার্ল লিপিটি এখানে রয়েছে: http://heinitz-it.de/download/enum2string/enum2string.pl.html


2

আপনার উত্তরগুলি আমাকে কিছু ম্যাক্রো লিখতে অনুপ্রাণিত করেছিল। আমার প্রয়োজনীয়তাগুলি নিম্নলিখিত ছিল:

  1. কেবল এনামের প্রতিটি মান একবার লিখুন, যাতে বজায় রাখার জন্য কোনও ডাবল তালিকা নেই

  2. এনাম মানগুলি একটি পৃথক ফাইলে রাখবেন না যা পরে # অন্তর্ভুক্ত রয়েছে, তাই আমি যেখানে চাই সেখানে এটি লিখতে পারি

  3. এনামটি নিজেই প্রতিস্থাপন করবেন না, আমি এখনও এনাম টাইপটি সংজ্ঞায়িত করতে চাই, তবে এটির পাশাপাশি আমি প্রতিটি এনামের নামটিকে সংশ্লিষ্ট স্ট্রিংয়ে মানচিত্র তৈরি করতে সক্ষম করতে চাই (লিগ্যাসি কোডটি প্রভাবিত না করে)

  4. অনুসন্ধানগুলি দ্রুত হওয়া উচিত, সুতরাং সেই বিশাল এনামগুলির জন্য পছন্দমতো কোনও স্যুইচ-কেস নেই

এই কোডটি কিছু মান সহ একটি ক্লাসিক এনাম তৈরি করে। এছাড়াও এটি স্টাডি :: ম্যাপ হিসাবে তৈরি করে যা প্রতিটি এনামের মানটিকে তার নামের সাথে মানচিত্র করে (যেমন মানচিত্র [E_SUNDAY] = "E_SUNDAY", ইত্যাদি)

ঠিক আছে, এখন কোড এখানে:

EnumUtilsImpl.h :

map<int, string> & operator , (map<int, string> & dest, 
                               const pair<int, string> & keyValue) {
    dest[keyValue.first] = keyValue.second; 
    return dest;
}

#define ADD_TO_MAP(name, value) pair<int, string>(name, #name)

EnumUtils.h // এই ফাইলটি আপনি যখনই অন্তর্ভুক্ত করতে চান যখনই আপনাকে এই জিনিসটি করার প্রয়োজন হবে, আপনি এটি থেকে ম্যাক্রোগুলি ব্যবহার করবেন:

#include "EnumUtilsImpl.h"
#define ADD_TO_ENUM(name, value) \
    name value

#define MAKE_ENUM_MAP_GLOBAL(values, mapName) \
    int __makeMap##mapName() {mapName, values(ADD_TO_MAP); return 0;}  \
    int __makeMapTmp##mapName = __makeMap##mapName();

#define MAKE_ENUM_MAP(values, mapName) \
    mapName, values(ADD_TO_MAP);

মাইপ্রজেক্টকোডফিল.এইচ // এটি একটি কাস্টম এনাম তৈরি করতে কীভাবে এটি ব্যবহার করবেন তার একটি উদাহরণ:

#include "EnumUtils.h*

#define MyEnumValues(ADD) \
    ADD(val1, ), \
    ADD(val2, ), \
    ADD(val3, = 100), \
    ADD(val4, )

enum MyEnum {
    MyEnumValues(ADD_TO_ENUM)
};

map<int, string> MyEnumStrings;
// this is how you initialize it outside any function
MAKE_ENUM_MAP_GLOBAL(MyEnumValues, MyEnumStrings); 

void MyInitializationMethod()
{ 
    // or you can initialize it inside one of your functions/methods
    MAKE_ENUM_MAP(MyEnumValues, MyEnumStrings); 
}

চিয়ার্স।


2

এখানে << এবং >> স্ট্রিম অপারেটরগুলি কেবলমাত্র এক লাইনের ম্যাক্রো কমান্ড দিয়ে স্বয়ংক্রিয়ভাবে এনামে নেওয়ার চেষ্টা করা হচ্ছে ...

সজ্ঞা:

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

যদিও এই প্রকল্পের সীমাবদ্ধতা সম্পর্কে নিশ্চিত নন ... মন্তব্য স্বাগত!


1

শিরোনামে:

enum EFooOptions
 {
FooOptionsA = 0, EFooOptionsMin = 0,
FooOptionsB,
FooOptionsC,
FooOptionsD 
EFooOptionsMax
};
extern const wchar* FOO_OPTIONS[EFooOptionsMax];

.cpp ফাইলে:

const wchar* FOO_OPTIONS[] = {
    L"One",
    L"Two",
    L"Three",
    L"Four"
};

ক্যাভেট: খারাপ অ্যারে সূচকটি পরিচালনা করবেন না। :) তবে আপনি অ্যারে থেকে স্ট্রিং পাওয়ার আগে এনাম যাচাই করতে সহজেই একটি ফাংশন যুক্ত করতে পারেন।


প্রকৃতপক্ষে একটি খুব অ-DRY-SPOT সমাধান।
xtofl

এখন আপনি DRY উল্লেখ। অন্য কোনও ইনপুট ফাইল থেকে স্বয়ংক্রিয়ভাবে উত্পন্ন .h এবং .cpp ফাইল। আমি আরও ভাল সমাধানগুলি দেখতে চাই (এটি অপ্রয়োজনীয় জটিলতার আশ্রয় নেয় না)
মোগস

1

আমি কেবল ম্যাক্রোগুলি ব্যবহার করে এই সম্ভাব্য মার্জিত সমাধানটি দেখাতে চেয়েছিলাম। এটি সমস্যার সমাধান করে না তবে আমি মনে করি সমস্যাটি সম্পর্কে পুনর্বিবেচনা করা ভাল উপায়।

#define MY_LIST(X) X(value1), X(value2), X(value3)

enum eMyEnum
    {
    MY_LIST(PLAIN)
    };

const char *szMyEnum[] =
    {
    MY_LIST(STRINGY)
    };


int main(int argc, char *argv[])
{

std::cout << szMyEnum[value1] << value1 <<" " <<  szMyEnum[value2] << value2 << std::endl;

return 0;
}

---- সম্পাদনা করুন ----

কিছু ইন্টারনেট গবেষণা এবং কিছু নিজস্ব ব্যয়ের পরে আমি নিম্নলিখিত সমাধানে এসেছি:

//this is the enum definition
#define COLOR_LIST(X) \
  X( RED    ,=21)      \
  X( GREEN  )      \
  X( BLUE   )      \
  X( PURPLE , =242)      \
  X( ORANGE )      \
  X( YELLOW )

//these are the macros
#define enumfunc(enums,value) enums,
#define enumfunc2(enums,value) enums value,
#define ENUM2SWITCHCASE(enums) case(enums): return #enums;

#define AUTOENUM(enumname,listname) enum enumname{listname(enumfunc2)};
#define ENUM2STRTABLE(funname,listname) char* funname(int val) {switch(val) {listname(ENUM2SWITCHCASE) default: return "undef";}}
#define ENUM2STRUCTINFO(spacename,listname) namespace spacename { int values[] = {listname(enumfunc)};int N = sizeof(values)/sizeof(int);ENUM2STRTABLE(enum2str,listname)};

//here the enum and the string enum map table are generated
AUTOENUM(testenum,COLOR_LIST)
ENUM2STRTABLE(testfunenum,COLOR_LIST)
ENUM2STRUCTINFO(colorinfo,COLOR_LIST)//colorinfo structur {int values[]; int N; char * enum2str(int);}

//debug macros
#define str(a) #a
#define xstr(a) str(a)


int main( int argc, char** argv )
{
testenum x = YELLOW;
std::cout << testfunenum(GREEN) << "   " << testfunenum(PURPLE) << PURPLE << "  " << testfunenum(x);

for (int i=0;i< colorinfo::N;i++)
std::cout << std::endl << colorinfo::values[i] <<  "  "<< colorinfo::enum2str(colorinfo::values[i]);

  return EXIT_SUCCESS;
}

আমি কেবল এটি পোস্ট করতে চেয়েছিলাম সম্ভবত কেউ এই সমাধানটি দরকারী খুঁজে পেতে পারে। টেমপ্লেট ক্লাসের প্রয়োজন নেই সি ++ 11 এবং বুস্টের দরকার নেই তাই এটি সাধারণ সি এর জন্যও ব্যবহার করা যেতে পারে

---- সম্পাদনা 2 ----

2 টিরও বেশি এনাম ব্যবহার করার সময় তথ্য সারণী কিছু সমস্যা তৈরি করতে পারে (সংকলক সমস্যা)। নিম্নলিখিত কাজের মতো কাজ করেছে:

#define ENUM2STRUCTINFO(spacename,listname) namespace spacename { int spacename##_##values[] = {listname(enumfunc)};int spacename##_##N = sizeof(spacename##_##values)/sizeof(int);ENUM2STRTABLE(spacename##_##enum2str,listname)};

1
typedef enum {
    ERR_CODE_OK = 0,
    ERR_CODE_SNAP,

    ERR_CODE_NUM
} ERR_CODE;

const char* g_err_msg[ERR_CODE_NUM] = {
    /* ERR_CODE_OK   */ "OK",
    /* ERR_CODE_SNAP */ "Oh, snap!",
};

উপরে আমার সহজ সমাধান। এর একটি উপকারিতা হ'ল NUM

স্ট্রিংটি পেতে আপনি কোনও ফাংশন সংজ্ঞায়িত করতে পারেন:

const char* get_err_msg(ERR_CODE code) {
    return g_err_msg[code];
}

আমার সমাধানের আরও পরে, আমি নিম্নলিখিতটি বেশ আকর্ষণীয় পেলাম। এটি সাধারণত উপরেরটির সিঙ্ক সমস্যার সমাধান করে।

স্লাইডগুলি এখানে: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724

এখানে কোড: https://github.com/arunksaha/enum_to_string


1

আমি জানি আমি পার্টি করতে দেরি করেছি, তবে অন্য যে কেউ এই পৃষ্ঠাটি দেখতে আসে তাদের জন্য আপনি এটি চেষ্টা করতে পারেন, সেখানকার সবকিছুর চেয়ে এটি সহজ এবং আরও জ্ঞানযুক্ত:

namespace texs {
    typedef std::string Type;
    Type apple = "apple";
    Type wood = "wood";
}

আপনি কি স্ট্রিং ব্যবহার করার পরামর্শ দিচ্ছেন এবং এনাম ব্যবহার করছেন না? এটি আসলেই সমস্যার সমাধান করে না।
রডি

0

আমি সম্প্রতি একটি বিক্রেতা গ্রন্থাগার (ফিনক্যাড) নিয়ে একই সমস্যাটি পেয়েছিলাম। ভাগ্যক্রমে, বিক্রেতা সমস্ত এনামগুলির জন্য এক্সএমএল ডকুমেন্টেশন সরবরাহ করেছিলেন। আমি প্রতিটি এনাম টাইপের জন্য একটি মানচিত্র তৈরি এবং প্রতিটি এনামের জন্য একটি অনুসন্ধানের ফাংশন সরবরাহ করে শেষ করেছি। এই কৌশলটি আপনাকে এনামের সীমা ছাড়াই কোনও লুক আটকানোর অনুমতি দেয়।

আমি নিশ্চিত সুইগ আপনার জন্য অনুরূপ কিছু করতে পারে তবে আমি রুবীতে লিখিত কোড জেনারেশন সরবরাহ করতে পেরে খুশি।

কোডের একটি নমুনা এখানে:

std::map<std::string, switches::FCSW2::type> init_FCSW2_map() {
        std::map<std::string, switches::FCSW2::type> ans;
        ans["Act365Fixed"] = FCSW2::Act365Fixed;
        ans["actual/365 (fixed)"] = FCSW2::Act365Fixed;
        ans["Act360"] = FCSW2::Act360;
        ans["actual/360"] = FCSW2::Act360;
        ans["Act365Act"] = FCSW2::Act365Act;
        ans["actual/365 (actual)"] = FCSW2::Act365Act;
        ans["ISDA30360"] = FCSW2::ISDA30360;
        ans["30/360 (ISDA)"] = FCSW2::ISDA30360;
        ans["ISMA30E360"] = FCSW2::ISMA30E360;
        ans["30E/360 (30/360 ISMA)"] = FCSW2::ISMA30E360;
        return ans;
}
switches::FCSW2::type FCSW2_lookup(const char* fincad_switch) {
        static std::map<std::string, switches::FCSW2::type> switch_map = init_FCSW2_map();
        std::map<std::string, switches::FCSW2::type>::iterator it = switch_map.find(fincad_switch);
        if(it != switch_map.end()) {
                return it->second;
        } else {
                throw FCSwitchLookupError("Bad Match: FCSW2");
        }
}

দেখে মনে হচ্ছে আপনি অন্য পথে যেতে চান (এনুম স্ট্রিংয়ের পরিবর্তে এনাম স্ট্রিং-এ), তবে এটি বিপরীতমুখী হওয়া উচিত।

-Whit


1
ক) অন্য কেউ এটিকে একেবারেই অপঠনযোগ্য মনে করে? কয়েক typedefs এবং ঘোষণা ব্যবহার করবে অতি পাঠযোগ্যতা উন্নতি। খ) স্থানীয় স্থির ঘোষণাগুলি থ্রেডসেফ নয়। গ) কনড স্ট্রিং ব্যবহার করুন এবং চর * এর পরিবর্তে, ডি) নিক্ষেপ ব্যতীত যে মানটি পাওয়া যায়নি তাকে অন্তর্ভুক্ত করার বিষয়ে কী?
অ্যালেস্টায়ার

0

নীচের সিনট্যাক্সটি আপনার উপযুক্ত কিনা তা দেখুন:

// WeekEnd enumeration
enum WeekEnd
{
    Sunday = 1,
    Saturday = 7
};

// String support for WeekEnd
Begin_Enum_String( WeekEnd )
{
    Enum_String( Sunday );
    Enum_String( Saturday );
}
End_Enum_String;

// Convert from WeekEnd to string
const std::string &str = EnumString<WeekEnd>::From( Saturday );
// str should now be "Saturday"

// Convert from string to WeekEnd
WeekEnd w;
EnumString<WeekEnd>::To( w, "Sunday" );
// w should now be Sunday

যদি এটি হয়, তবে আপনি এই নিবন্ধটি দেখতে চান:
http://www.gamedev.net/references/snippets/features/cppstringizing/


0

এই ডান পুরানো জগাখিচাটি এসও থেকে বিট এবং পিসগুলির উপর ভিত্তি করে আমার প্রচেষ্টা। 20 টিরও বেশি এনাম মান সমর্থন করার জন্য ফর_ইচটি প্রসারিত করতে হবে। ভিজ্যুয়াল স্টুডিও 2019, ঝনঝন এবং জিসিসিতে এটি পরীক্ষা করেছে। C ++ 11

#define _enum_expand(arg) arg
#define _enum_select_for_each(_,_0, _1, _2,_3,_4, _5, _6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,N, ...) N
#define _enum_for_each_0(_call, arg0,arg1,...)
#define _enum_for_each_1(_call, arg0,arg1) _call(arg0,arg1)
#define _enum_for_each_2(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_1(_call,arg0, __VA_ARGS__))
#define _enum_for_each_3(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_2(_call,arg0, __VA_ARGS__))
#define _enum_for_each_4(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_3(_call,arg0, __VA_ARGS__))
#define _enum_for_each_5(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_4(_call,arg0, __VA_ARGS__))
#define _enum_for_each_6(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_5(_call,arg0, __VA_ARGS__))
#define _enum_for_each_7(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_6(_call,arg0, __VA_ARGS__))
#define _enum_for_each_8(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_7(_call,arg0, __VA_ARGS__))
#define _enum_for_each_9(_call, arg0,arg1, ...) _call(arg0,arg1)  _enum_expand(_enum_for_each_8(_call,arg0, __VA_ARGS__))
#define _enum_for_each_10(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_9(_call,arg0, __VA_ARGS__))
#define _enum_for_each_11(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_10(_call,arg0, __VA_ARGS__))
#define _enum_for_each_12(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_11(_call,arg0, __VA_ARGS__))
#define _enum_for_each_13(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_12(_call,arg0, __VA_ARGS__))
#define _enum_for_each_14(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_13(_call,arg0, __VA_ARGS__))
#define _enum_for_each_15(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_14(_call,arg0, __VA_ARGS__))
#define _enum_for_each_16(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_15(_call,arg0, __VA_ARGS__))
#define _enum_for_each_17(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_16(_call,arg0, __VA_ARGS__))
#define _enum_for_each_18(_call, arg0,arg1, ...) _call(arg0,arg1) _enum_expand(_enum_for_each_17(_call,arg0, __VA_ARGS__))
#define _enum_for_each_19(_call, arg0,arg1, ...) _call(arg) _enum_expand(_enum_for_each_18(_call,arg0, __VA_ARGS__))
#define _enum_for_each(arg, ...) \
    _enum_expand(_enum_select_for_each(_, ##__VA_ARGS__, \
    _enum_for_each_19, _enum_for_each_18, _enum_for_each_17, _enum_for_each_16, _enum_for_each_15, \
    _enum_for_each_14, _enum_for_each_13, _enum_for_each_12, _enum_for_each_11, _enum_for_each_10, \
    _enum_for_each_9,  _enum_for_each_8,  _enum_for_each_7,  _enum_for_each_6,  _enum_for_each_5,  \
    _enum_for_each_4,  _enum_for_each_3,  _enum_for_each_2,  _enum_for_each_1,  _enum_for_each_0)(arg, ##__VA_ARGS__))

#define _enum_strip_args_1(arg0) arg0
#define _enum_strip_args_2(arg0, arg1) arg0, arg1
#define _enum_make_args(...) (__VA_ARGS__)

#define _enum_elem_arity1_1(arg) arg,
#define _enum_elem_arity1( ...) _enum_expand(_enum_elem_arity1_1 __VA_ARGS__)
#define _enum_elem_arity2_1(arg0,arg1) arg0 = arg1,
#define _enum_elem_arity2( ...) _enum_expand(_enum_elem_arity2_1 __VA_ARGS__)

#define _enum_elem_select_arity_2(_0, _1, NAME,...) NAME
#define _enum_elem_select_arity_1(...) _enum_expand(_enum_elem_select_arity_2(__VA_ARGS__, _enum_elem_arity2,_enum_elem_arity1,_))
#define _enum_elem_select_arity(enum_type,...) _enum_expand(_enum_elem_select_arity_1 __VA_ARGS__)(__VA_ARGS__)

#define _enum_str_arity1_1(enum_type,arg) { enum_type::arg,#arg },
#define _enum_str_arity1(enum_type,...) _enum_expand(_enum_str_arity1_1 _enum_make_args( enum_type, _enum_expand(_enum_strip_args_1 __VA_ARGS__)))
#define _enum_str_arity2_1(enum_type,arg,value) { enum_type::arg,#arg },
#define _enum_str_arity2(enum_type, ...) _enum_expand(_enum_str_arity2_1 _enum_make_args( enum_type, _enum_expand(_enum_strip_args_2 __VA_ARGS__)))
#define _enum_str_select_arity_2(_0, _1, NAME,...) NAME
#define _enum_str_select_arity_1(...) _enum_expand(_enum_str_select_arity_2(__VA_ARGS__, _enum_str_arity2,_enum_str_arity1,_))
#define _enum_str_select_arity(enum_type,...) _enum_expand(_enum_str_select_arity_1 __VA_ARGS__)(enum_type,__VA_ARGS__)

#define error_code_enum(enum_type,...)  enum class enum_type {              \
    _enum_expand(_enum_for_each(_enum_elem_select_arity,enum_type, ##__VA_ARGS__))};  \
    namespace _ ## enum_type ## _detail { \
        template <typename> struct _ ## enum_type ## _error_code{ \
            static const std::map<enum_type, const char*> enum_type ## _map; \
        }; \
            template <typename T> \
            const std::map<enum_type, const char*> _ ## enum_type ## _error_code<T>::enum_type ## _map = { \
                _enum_expand(_enum_for_each(_enum_str_select_arity,enum_type,  ##__VA_ARGS__)) \
        }; \
    } \
    inline const char* get_error_code_name(const enum_type& value) { \
        return _ ## enum_type ## _detail::_ ## enum_type ## _error_code<enum_type>::enum_type ## _map.find(value)->second; \
    } 

error_code_enum(myenum,
    (one, 1),
    (two)
);

যা নিম্নলিখিত কোড উত্পাদন করে

enum class myenum { 
    one = 1,
    two,
};
namespace _myenum_detail {
    template <typename>
    struct _myenum_error_code {
        static const std::map<myenum, const char*> myenum_map;
    };
    template <typename T>
    const std::map<myenum, const char*> _myenum_error_code<T>::myenum_map = {
        { myenum::one, "one" }, 
        { myenum::two, "two" },
    };
}
inline const char* get_error_code_name(const myenum& value) { 
    return _myenum_detail::_myenum_error_code<myenum>::myenum_map.find(value)->second; 
}

এমন লজ্জাজনক হুপস আপনাকে বিশ্বের সবচেয়ে ব্যবহৃত প্রোগ্রামিং ভাষাগুলির একটিতে এটি করার জন্য প্রিপ্রোসেসর দিয়ে ঝাঁপিয়ে পড়তে হবে ...

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.