C++: Print out enum value as text
Solution 1:
Using map:
#include <iostream>
#include <map>
#include <string>
enum Errors {ErrorA=0, ErrorB, ErrorC};
std::ostream& operator<<(std::ostream& out, const Errors value){
static std::map<Errors, std::string> strings;
if (strings.size() == 0){
#define INSERT_ELEMENT(p) strings[p] = #p
INSERT_ELEMENT(ErrorA);
INSERT_ELEMENT(ErrorB);
INSERT_ELEMENT(ErrorC);
#undef INSERT_ELEMENT
}
return out << strings[value];
}
int main(int argc, char** argv){
std::cout << ErrorA << std::endl << ErrorB << std::endl << ErrorC << std::endl;
return 0;
}
Using array of structures with linear search:
#include <iostream>
#include <string>
enum Errors {ErrorA=0, ErrorB, ErrorC};
std::ostream& operator<<(std::ostream& out, const Errors value){
#define MAPENTRY(p) {p, #p}
const struct MapEntry{
Errors value;
const char* str;
} entries[] = {
MAPENTRY(ErrorA),
MAPENTRY(ErrorB),
MAPENTRY(ErrorC),
{ErrorA, 0}//doesn't matter what is used instead of ErrorA here...
};
#undef MAPENTRY
const char* s = 0;
for (const MapEntry* i = entries; i->str; i++){
if (i->value == value){
s = i->str;
break;
}
}
return out << s;
}
int main(int argc, char** argv){
std::cout << ErrorA << std::endl << ErrorB << std::endl << ErrorC << std::endl;
return 0;
}
Using switch/case:
#include <iostream>
#include <string>
enum Errors {ErrorA=0, ErrorB, ErrorC};
std::ostream& operator<<(std::ostream& out, const Errors value){
const char* s = 0;
#define PROCESS_VAL(p) case(p): s = #p; break;
switch(value){
PROCESS_VAL(ErrorA);
PROCESS_VAL(ErrorB);
PROCESS_VAL(ErrorC);
}
#undef PROCESS_VAL
return out << s;
}
int main(int argc, char** argv){
std::cout << ErrorA << std::endl << ErrorB << std::endl << ErrorC << std::endl;
return 0;
}
Solution 2:
Use an array or vector of strings with matching values:
char *ErrorTypes[] =
{
"errorA",
"errorB",
"errorC"
};
cout << ErrorTypes[anError];
EDIT: The solution above is applicable when the enum is contiguous, i.e. starts from 0 and there are no assigned values. It will work perfectly with the enum in the question.
To further proof it for the case that enum doesn't start from 0, use:
cout << ErrorTypes[anError - ErrorA];
Solution 3:
Here is an example based on Boost.Preprocessor:
#include <iostream>
#include <boost/preprocessor/punctuation/comma.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#define DEFINE_ENUM(name, values) \
enum name { \
BOOST_PP_SEQ_FOR_EACH(DEFINE_ENUM_VALUE, , values) \
}; \
inline const char* format_##name(name val) { \
switch (val) { \
BOOST_PP_SEQ_FOR_EACH(DEFINE_ENUM_FORMAT, , values) \
default: \
return 0; \
} \
}
#define DEFINE_ENUM_VALUE(r, data, elem) \
BOOST_PP_SEQ_HEAD(elem) \
BOOST_PP_IIF(BOOST_PP_EQUAL(BOOST_PP_SEQ_SIZE(elem), 2), \
= BOOST_PP_SEQ_TAIL(elem), ) \
BOOST_PP_COMMA()
#define DEFINE_ENUM_FORMAT(r, data, elem) \
case BOOST_PP_SEQ_HEAD(elem): \
return BOOST_PP_STRINGIZE(BOOST_PP_SEQ_HEAD(elem));
DEFINE_ENUM(Errors,
((ErrorA)(0))
((ErrorB))
((ErrorC)))
int main() {
std::cout << format_Errors(ErrorB) << std::endl;
}
Solution 4:
You can use a simpler pre-processor trick if you are willing to list your enum
entries in an external file.
/* file: errors.def */
/* syntax: ERROR_DEF(name, value) */
ERROR_DEF(ErrorA, 0x1)
ERROR_DEF(ErrorB, 0x2)
ERROR_DEF(ErrorC, 0x4)
Then in a source file, you treat the file like an include file, but you define what you want the ERROR_DEF
to do.
enum Errors {
#define ERROR_DEF(x,y) x = y,
#include "errors.def"
#undef ERROR_DEF
};
static inline std::ostream & operator << (std::ostream &o, Errors e) {
switch (e) {
#define ERROR_DEF(x,y) case y: return o << #x"[" << y << "]";
#include "errors.def"
#undef ERROR_DEF
default: return o << "unknown[" << e << "]";
}
}
If you use some source browsing tool (like cscope), you'll have to let it know about the external file.
Solution 5:
This is a good way,
enum Rank { ACE = 1, DEUCE, TREY, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING };
Print it with an array of character arrays
const char* rank_txt[] = {"Ace", "Deuce", "Trey", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Four", "King" } ;
Like this
std::cout << rank_txt[m_rank - 1]