Re: How to elegantly get the enum code from its string type
On Apr 13, 6:53 pm, thomas <freshtho...@gmail.com> wrote:
enum Type{
REPLY = 100,
REP = 1052,
HAHA = 9523,};
When I open the interface to users for configuration, I would like the
user to use "REPLY", "REP", "HAHA" like string format because it's
much easier to recognize and remember.
But in my program, I need to use the actual code (integral format).
My solution is to define a map<string, int>, and insert the string and
integral format pairs into the map for query. But it's really anoying
and difficult to use, especially when initializing.
Is there any elegant solution to this problem?
Not that I'm aware of. A simplified version of my preferred approach
follows (hacked up in half an hour, so expect to need a tweak or two)
- there's a bit of stuff you can throw in a header, then the usage is:
BENUM(Identifier, value-list...)
To create "class Identifier" implicitly convertible to/from an enum
with the listed values, with an operator<< provided. operator>> can
be trivially added.
The downside is that the identifier<->value associations are created
at run-time on first use, so there's a slight performance impact. As
presented here, I'm lazy and create strings willy-nilly, though it's
trivial to write and apply a "read-only string class" based around a
const char* and size_t.
A totally over-engineered version supporting streaming in and out,
custom containers for value/identifier association, markup for
implicit values and bit flags etc. is available in benum_v1.zip at the
Boost Vault, though in hindsight I feel I should have focused on
simpler use cases. Should finish it off, but nobody's asking me to
and I'm lazy.
Cheers,
Tony
// benum support code... (put in a header)
#include <iostream>
#include <string>
#include <map>
namespace Benum
{
struct Meta
{
Meta(const char* p, int* p_values)
{
while (*p)
{
if (isalnum(*p) || *p == '_')
{
const char* p_from = p;
while (isalnum(*p) || *p == '_')
++p;
std::string idn = std::string(p_from, p - p_from);
// std::cout << "meta " << idn << '=' << *p_values
<< '\n';
int_to_string_[*p_values] = idn;
string_to_int_[idn] = *p_values;
++p_values;
}
else if (*p == '=')
while (*p && *p != ',')
++p;
else
++p;
}
}
std::ostream& out(std::ostream& os, int i) const
{
Int_To_String::const_iterator it = int_to_string_.find(i);
if (it != int_to_string_.end())
return os << it->second;
else
return os << "<unmatched enum " << i << '>';
}
typedef std::map<int, std::string> Int_To_String;
std::map<int, std::string> int_to_string_;
std::map<std::string, int> string_to_int_;
};
template <typename T>
struct Incrementing
{
Incrementing(int n) : n_(n) { s_next_implicit_ = n + 1; }
Incrementing() : n_(s_next_implicit_++) { }
operator int() const { return n_; }
int n_;
static int s_next_implicit_;
};
template <typename T>
int Incrementing<T>::s_next_implicit_;
}
#define BENUM(IDN, ...) \
enum IDN ## _Enum { __VA_ARGS__ }; \
class IDN { \
typedef IDN ## _Enum Enum; \
IDN(Enum e) : e_(e) { } \
IDN& operator=(Enum e) { e_ = e; return *this; } \
operator Enum() const { return e_; } \
friend std::ostream& operator<<(std::ostream& os, Enum e) { \
return IDN::meta().out(os, e); \
} \
static const Benum::Meta& meta() { \
static Benum::Incrementing<IDN> __VA_ARGS__; \
static int values[] = { __VA_ARGS__ }; \
static Benum::Meta m(#__VA_ARGS__, values); \
return m; \
} \
Enum e_; \
};
// benum example usage...
BENUM(Type, One = 1, Two = 2, Three = 3, Four = 4, Whats_Next);
int main()
{
std::cout << One << ' ' << Two << ' ' << Three << ' ' <<
Whats_Next << '\n';
}