可能重复:
Enum to string : return the enum integer value if invalid / not found
简而言之,我所拥有的(工作)定义代码是这样的:
enum Gadget
{
First,
Second,
};
const char* gadget_debug_names[] = {
"First",
"Second",
// note: strings are same as enum tokens here, but bonus points if
// they can optionally be given different values
};
但是,如果信息位于必须手动维护的多个单独位置,则容易出错。 (在某些情况下,在代码库中,我正在使用这两个 - 或更多 - 地方甚至不在同一个文件中。)所以,只要将这些东西命名一次就会非常好。
现在我们可以使用代码生成和声明性数据文件来完成此操作,但是如果有更好的方法,我宁愿不向现有的构建过程添加另一个步骤。有一些看起来像
的东西是完美的DEFINE_GADGET(First)
DEFINE_GADGET(Second)
(如果需要,可选择启动/停止宏)但是,由于宏只是纯文本替换,我无法想出让预处理器在写出枚举定义时“记住”令牌的任何方法。
我认为这也可能通过元编程实现,但我对如何做到这一点感到茫然。我在那里看到的所有例子都涉及递归地构建数据结构。我可以看到我如何以这种方式构建字符串数组,但我不确定如何传递令牌名称,或者如何构建枚举。 (当然,使用元编程来构建一个字符串数组会非常荒谬。)
有没有办法让我在这里保持DRY,而不使用代码生成?
答案 0 :(得分:11)
有一个旧的预处理器技巧:
DEFINE_GADGET(First)
DEFINE_GADGET(Second)
#define QUOTE_VAL(X) #X
enum Gadget
{
#define DEFINE_GADGET(X) X,
#include "Gadget.data"
#undef DEFINE_GADGET(X)
};
const char* gadget_debug_names[] = {
#define DEFINE_GADGET(X) QUOTE_VAL(X),
#include "Gadget.data"
#undef DEFINE_GADGET(X)
};
答案 1 :(得分:1)
您可能想要或可能不想做的事情,首先定义要定义的内容,在本例中为枚举和char数组:
#define DEFENUM(v) v,
#define DEFENUM_last(v) v
#define DEFINE_ENUM(n, LIST) enum n { LIST(DEFENUM) }
#define DEFARR(v) #v,
#define DEFARR_last(v) #v
#define DEFINE_ARRAY(n, LIST) const char *n[] = { LIST(DEFARR) }
然后使用以下格式制作您的列表:
#define LETTERS(GEN) \
GEN(aaa) \
GEN(bbb) \
GEN(ccc) \
GEN(ddd) \
GEN##_last(eee)
或者这个:
#define LETTERS(GEN) \
GEN(aaa) GEN(bbb) GEN(ccc) GEN(ddd) GEN##_last(eee)
最后创建你想要创建的内容:
DEFINE_ENUM(LettersEnum, LETTERS);
DEFINE_ARRAY(letters_array, LETTERS);
这将转换为:
enum LettersEnum { aaa, bbb, ccc, ddd, eee };
const char *letters_array[] = { "aaa", "bbb", "ccc", "ddd", "eee" };
答案 2 :(得分:0)
我使用的简短示例:
#include <iostream>
#include <cassert>
#include "boost/preprocessor.hpp"
#include "boost/algorithm/string/predicate.hpp"
#define ENUMIFY_FOREACH( r, data, elem ) \
BOOST_PP_STRINGIZE( elem ) BOOST_PP_COMMA()
#define ENUMIFY( name, values ) \
struct name \
{ \
static const unsigned int Size = BOOST_PP_SEQ_SIZE( values ); \
typedef enum{ \
BOOST_PP_SEQ_ENUM( values ) \
} Values; \
static const char* (&Mappings())[ Size ] \
{ \
static const char* mappings[] = \
{ \
BOOST_PP_SEQ_FOR_EACH( ENUMIFY_FOREACH, _, values ) \
}; \
return mappings; \
}; \
static const char* String( Values a_Val ) \
{ \
return Mappings()[ static_cast< unsigned int >( a_Val ) ]; \
} \
static Values Value( const char* a_Key ) \
{ \
for( unsigned int i = 0; i < Size; ++i ) \
if( boost::iequals( a_Key, Mappings()[i] ) ) return static_cast< Values >( i ); \
assert( 0 && "Didn't find the value of string " ); \
return static_cast< Values >( 0 ); \
} \
\
};
ENUMIFY( SomeEnum, (Long)(Short)(Etc) );
int main()
{
std::cout << SomeEnum::String( SomeEnum::Long ) << std::endl; // Outputs Long
}