Equivalent of Enum for Strings

I studied enums which expects only integer inputs and returns corresponding value to it.I want to achieve same thing but I only have strings as a input. I want to make following work -

enum Types {
"Absolute", //"abs"
"PURE" , //"PRE"
"MIXED" //"MXD"
}

and probable statment could be -
string sTpes = Types("abs"); //this should return "Absolute"
or
string sTpes = Types("MXD"); //this should return "MIXED"

If not using enums ,please suggest me possible ways to achieve this.

Thanks.
Last edited on
You need a lookup table and/or function.

Perhaps this can help you to select on a string:
http://www.cplusplus.com/forum/general/11460/#msg54095
(scroll down to the second code block).

Hope this helps.
Also you can do something like this:
1
2
3
4
5
6
enum { abs = 0, PRE, MXD };
const char *types[] = { "Absolute", "PURE", "MIXED" };

...

string sTpes = types[abs];
forstudy3 -- as Duosa said, you'll need a lookup function; best table driven if you have more than a few values.

As you can't constrain string values, I define a special enum value to return if no strings match. Something like unknown or invalid

enum Types {
typeINVALID = -1,
typeABSOLUTE = 0, //"abs"
typePURE, //"PRE"
typeMIXED //"MXD"
};

(I use -1 for invalid as this is consistent with assorted other APIs)

Andy


Last edited on
Another good option:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
#include <map>

int main()
{
    std::map<std::string, std::string> types;

    types["abs"] = "Absolute";
    types["PRE"] = "PURE";
    types["MXD"] = "MIXED";

    std::cout
        << "types[\"abs\"] = \"" << types["abs"] << "\"\n"
        << "types[\"PRE\"] = \"" << types["PRE"] << "\"\n"
        << "types[\"MXD\"] = \"" << types["MXD"] << "\""
        << std::endl;

    return 0;
}
m4ster r0shi - would you use a map for just 3 values?
What would you suggest? I mean, show me a working example of how you would do it.
Last edited on
Well, for small number of enums I just use if-else.

But I was being genuinely curious, rather than critical. As I'm between jobs I'm taking the chance to revisit all the decisions I've made so far (in time for my job interviews...)

I would return an enum rather than a string, e.g.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Parse Genre name
inline bool ParseGenreName(const char* name, E_GENRE& value)
{
	using namespace Utils;

	bool retVal = true;

	value = GENRE_UNKNOWN;

	if(CompareNoAccents(name, "unknown") == 0)
		value = GENRE_UNKNOWN;
	else if(CompareNoAccents(name, "impossible") == 0)
		value = GENRE_IMPOSSIBLE;
	else if(CompareNoAccents(name, "masculin") == 0)
		value = GENRE_MASCULIN;
	else if(CompareNoAccents(name, "feminin") == 0)
		value = GENRE_FEMININ;
	else if(CompareNoAccents(name, "neutre") == 0)
		value = GENRE_NEUTRE;
	else
		retVal = false;

	return retVal;
} 


where

1
2
3
4
5
6
7
8
9
// Genre
enum E_GENRE
{
	GENRE_UNKNOWN    = -1,
	GENRE_IMPOSSIBLE = 0,
	GENRE_MASCULIN   = 1,
	GENRE_FEMININ    = 2,
	GENRE_NEUTRE     = 3,
};


Note
[1] CompareNoAccents() -- in namespace Utils -- converts all accented chars to their unaccented equivalent and then calls stricmp() or strcasecmp() -- depending on build
[2] I am not guarding against NULL pointers here, as that's done a level up
[3] This code is called by a C-based XML parser, as well as the config GUI, so I am avoiding the use of exceptions here (so I don't mis return codes and exception in the parsing code)

It could be modified to return a string via the out param, but I would use enum values internally and then map the enum back to a string for display purposes.
Last edited on

Enumerated types are types that are enumerated - obviously. Why/how would you enumerate a string? That completely defeats the purpose of enumerated types; therefore convoluting your code entirely. Just create a namespace holding your constants and move on.
Last edited on
andywestken wrote:
But I was being genuinely curious, rather than critical.

What makes you think I thought you were being critical?

andywestken wrote:
Well, for small number of enums I just use if-else.

I see. Even though a map's lookup complexity is O(logn), you prefer a
linear search in this case, as the constant factor is (probably) smaller.

But is it really worth it? Is this function really going to be the speed bottleneck of your app?
If yes, there are ways you can achieve O(logn) time complexity without the map overhead.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Parse Genre name
inline bool ParseGenreName(const char* name, E_GENRE& value)
{
    using namespace Utils;

    bool retVal = true;

    value = GENRE_UNKNOWN;

    if (name[0] < 'm')
    {
        if(CompareNoAccents(name, "feminin") == 0)
            value = GENRE_FEMININ;
        else if(CompareNoAccents(name, "impossible") == 0)
            value = GENRE_IMPOSSIBLE;
        else
            retVal = false;
    }
    else if (name[0] < 'n')
    {
        if(CompareNoAccents(name, "masculin") == 0)
            value = GENRE_MASCULIN;
        else
            retVal = false;
    }
    else
    {
        if(CompareNoAccents(name, "neutre") == 0)
            value = GENRE_NEUTRE;
        else if(CompareNoAccents(name, "unknown") == 0)
            value = GENRE_UNKNOWN;
        else
            retVal = false;
    }

    return retVal;
}

If no, I don't see a reason why you should sacrifice code cleanliness
for speed. In this case, I believe that a map would perform just fine.
Well, this code is not esp. speed critical. So as you say, with a small number of strings to test, the penalty of a linear search will (probably) be minor.

For larger sets of string/id mappings I would trade up to map, and then unorder_map/hash_map. But I wouldn't expect to come across an enum which requires this treatment.

But I would use map::find() to retrieve the id, rather than [], so I could handle not found.

Andy

I didn't assume you were being ciritical; I just decided to make my motivation as clear as possible.
Topic archived. No new replies allowed.