8

私が使用している外部コードには列挙型があります:

enum En {VALUE_A, VALUE_B, VALUE_C};

私が使用している別の外部コードには、3 つの #define ディレクティブがあります。

#define ValA 5
#define ValB 6
#define ValC 7

多くの場合、ValA、ValB、または ValC に等しい int X があり、対応する En の値 (ValA から VALUE_A、ValB から VALUEB など) にキャストする必要があります。そして、逆の操作をしなければならないことが何度もあり、enum Enum を ValA、ValB、または ValC に変換します。これらの関数のシグネチャを変更することはできません。そのような関数はたくさんあります。

問題は、翻訳をどのように行うかです。暗黙的に使用される 2 つのキャスト演算子を作成する必要がありますか? または、明示的に使用される2つの翻訳関数が必要です:

En ToEn(int)
int FromEn(En)

または他の解決策はありますか?

4

5 に答える 5

11

ここでキャストすることはできないため、無料の関数を使用します。変換が必要な他の列挙型がある可能性がある場合は、組み込みのキャストのように見えるようにしてください。

template<typename T>
T my_enum_convert(int);

template<>
En my_enum_convert<En>(int in) {
    switch(in) {
        case ValA: return VALUE_A;
        case ValB: return VALUE_B;
        case ValC: return VALUE_C;
        default: throw std::logic_error(__FILE__ ": enum En out of range");
    }
}

int my_enum_convert(En in) {
    switch(in) {
        case VALUE_A: return ValA;
        case VALUE_B: return ValB;
        case VALUE_C: return ValC;
        // no default, so that GCC will warn us if we've forgotten a case
    }
}

En enumValue = my_enum_convert<En>(ValA);
int hashDefineValue = my_enum_convert(VALUE_A);
enumValue = my_enum_convert<En>(0); // throws exception

またはそのようなもの-使用中に問題が発生した場合は調整する場合があります。

暗黙的な変換を使用しない理由は、En から int への暗黙的な変換が既に存在し、間違った答えが得られるためですそれを正しい答えを与えるものに確実に置き換えることができたとしても、結果のコードは変換を行っているようには見えません。IMO これは、変換ルーチンへの呼び出しを入力することよりも、後でコードを見る人を妨げることになります。

int への変換と int からの変換で非常に異なる外観にしたい場合は、テンプレートと関数に異なる名前を付けることができます。

あるいは、それらを同じように (そしてより static_cast に似せて) 表示したい場合は、次のようにすることができます。

template<typename T>
T my_enum_convert(En in) {
    switch(in) {
        case VALUE_A: return ValA;
        case VALUE_B: return ValB;
        case VALUE_C: return ValC;
    }
}

int hashDefineValue = my_enum_convert<int>(VALUE_A);

書かれているように、T には int からの暗黙的な変換が必要です。明示的な変換のみを持つ T をサポートする場合は、「return T(ValA);」を使用します。代わりに (または、"return static_cast<T>(ValA);"、単一引数のコンストラクターが C スタイルのキャストであり、したがって許容されないと考える場合)。

于 2008-12-15T11:14:39.797 に答える
2

暗黙のキャストは変換関数よりも便利ですが、何が起こっているのかわかりにくいという欠点もあります。便利で明白なアプローチは、オーバーロードされたキャスト演算子で独自のクラスを使用することです。カスタム型を enum または int にキャストする場合、一部のカスタム キャストを見逃すことは容易ではありません。

なんらかの理由でこのためのクラスを作成できない場合は、コードを記述する際の利便性よりもメンテナンス中の読みやすさの方が重要であるため、翻訳関数を使用します。

于 2008-12-15T09:22:54.793 に答える
1

関数を持っていて、ライブラリ関数をオーバーロードしますか?

//libFunc( enum a );

libFuncOverload( define a ) {
    libFunc( toEn( a ) );
}
于 2008-12-15T09:15:50.003 に答える
1

列挙型の演算子をオーバーロードすることはできません。または、何か不足していますか?まあ、あなたはある種のダミークラスを作成することができます。それは int を受け取る暗黙のコンストラクターを持ち、次に enum へのキャスト演算子 (およびその逆) を持ちます。

したがって、唯一の解決策は関数を持つことです。また、パトリックが提案するように、オーバーロードを作成します。

于 2008-12-15T09:18:36.987 に答える
-1

enumからintへの変換(int(VALUE_A)など)は、自動的に/透過的に行われます。

intからenum(En(ValA)など)への変換、intenumの有効なメンバーであることを確認するための健全性チェックの恩恵を受けることができます。(ただし、ライブラリコードは、そもそも列挙値が有効である とは想定していません。)

intx」の場合には役立ちませんが、次のように変更することで多少役立つことがあります。

#define ValA 5

に:

#define ValA VALUE_A

列挙型En()がどこにでも含まれ/定義されている場合、ValAとVALUE_Aの両方foo (int)bar(En)の両方で自動的に/透過的に機能します。

あなたが使用することができます:

#ifdef ValA
STATIC_ASSERT( ValA == VALUE_A, ValA_equal_VALUE_A );
#undef ValA
#else
#warning "ValA undefined.  Defining as VALUE_A"
#endif
#define ValA VALUE_A

STATIC_ASSERTは次のようなものです

    /* Use CONCATENATE_4_AGAIN to expand the arguments to CONCATENATE_4 */
#define CONCATENATE_4(      a,b,c,d)  CONCATENATE_4_AGAIN(a,b,c,d)
#define CONCATENATE_4_AGAIN(a,b,c,d)  a ## b ## c ## d

    /* Creates a typedef that's legal/illegal depending on EXPRESSION.       *
     * Note that IDENTIFIER_TEXT is limited to "[a-zA-Z0-9_]*".              *
     * (This may be replaced by static_assert() in future revisions of C++.) */
#define STATIC_ASSERT( EXPRESSION, IDENTIFIER_TEXT)                     \
  typedef char CONCATENATE_4( static_assert____,      IDENTIFIER_TEXT,  \
                              ____failed_at_line____, __LINE__ )        \
            [ (EXPRESSION) ? 1 : -1 ]
于 2008-12-15T10:31:58.603 に答える