10

重複の可能性:
Enum to string : 無効/見つからない場合は列挙整数値を返します

簡単に言うと、私が持っている (作業中の) 定義コードは次のようなものです。

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

ただし、情報が複数の別々の場所にあり、手動で維持する必要があるため、エラーが発生しやすくなります。(コードベースでは、これらの 2 つ以上の場所を扱っている場合もありますが、現在は同じファイルに含まれていません。) したがって、これらの名前を 1 回だけ指定するのは非常に便利です。

コード生成と宣言型データ ファイルを使用してこれを行うことができますが、これを行うためのより良い方法があれば、既存のビルド プロセスに別のステップを追加したくありません。次のようなものがあれば完璧です

DEFINE_GADGET(First)
DEFINE_GADGET(Second)

(オプションで、必要に応じて開始/停止マクロを使用)しかし、マクロはプレーンテキストの置換にすぎないため、プリプロセッサが列挙定義を書き出すときにトークンを「記憶」させる方法がわかりません。

メタプログラミングでもできるのではないかと思っていたのですが、どうしたらいいのか途方に暮れています。そこで見たすべての例には、データ構造を再帰的に構築することが含まれています。文字列の配列をそのように構築する方法はわかりますが、トークン名を渡す方法や列挙型を構築する方法がわかりません。(もちろん、文字列の配列を構築するためだけにメタプログラミングを使用するのは、かなりばかげています。)

コード生成を使用せずに、ここで DRY を維持する方法はありますか?

4

3 に答える 3

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)
};
于 2012-10-31T09:21:29.387 に答える
1

やりたいこともやりたくないこともありますが、最初に何を定義するかを定義します。この場合は列挙型と文字配列です。

#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" };
于 2012-10-31T11:58:08.863 に答える
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
}
于 2012-10-31T09:26:40.793 に答える