8

在我使用的外部代码中有枚举:

enum En {VALUE_A, VALUE_B, VALUE_C};

在我使用的另一个外部代码中,有 3 个 #define 指令:

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

很多时候我有 int X 等于 ValA 或 ValB 或 ValC,我必须将它转换为 En 的相应值(ValA 到 VALUE_A,ValB 到 VALUEB 等),因为某些函数签名具有枚举 En。很多时候我必须做相反的操作,将 enum En 转换为 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,然后有一个强制转换运算符到一个枚举(反之亦然)。

因此,唯一的解决方案是拥有功能。另外,我会按照帕特里克的建议进行重载。

于 2008-12-15T09:18:36.987 回答
-1

enum 转换为 int,例如 int(VALUE_A),会自动/透明地发生。

int 转换为 enum,例如En(ValA)可以从完整性检查中受益,以确保int值是枚举的有效成员。 (虽然希望库代码不假设它的枚举值首先是有效的。)

虽然它对“ int x ”情况没有帮助,但您可以通过更改来有所帮助:

#define ValA 5

到:

#define ValA VALUE_A

如果enum En()在任何地方都包含/定义, ValAVALUE_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 回答