【问题标题】:error: ambiguous default type conversion (c++)错误:不明确的默认类型转换(C++)
【发布时间】:2011-07-31 06:41:41
【问题描述】:

我有一个包含枚举的类,以便于打印、序列化等。
我希望能够在 switch 语句中使用它作为传统的枚举,因此在 gcc-4.3 之前我一直使用 int() 重载器。但是,我的代码现在因 gcc-4.5.1 而中断。

enum E { consta, constb };
class Wrap {
 private:
  E e;
 public:
  operator E() { return e;}
  operator E() const { return e;}
  operator int() const { return e;} 
  Wrap(E a) : e(a) { }
};

int main() {
  Wrap x(constb);
  x = consta;
  switch (x) { /* Error here */
    case consta: // ..
    case constb: // ..
  }   
  return 0;
} 

编译器错误是:
错误:来自“Wrap”的模棱两可的默认类型转换
错误:候选转换包括 'Wrap::operator E() const' 和 'Wrap::operator int() const'

这是库的一部分,我希望代码适用于所有版本,因此删除 int 重载器不是一种选择。

【问题讨论】:

  • 为什么需要非常量 operator E()

标签: c++ gcc


【解决方案1】:

如果您专门解决编译器错误,只需使用条件编译来创建解决方法并使其尽可能独立。

#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40300
    typedef int E; // workaround
#   define ENUM_TYPE // do not define an enum type as it's not fully supported
#else
#   define ENUM_TYPE E // newer GCC supports enum better
#endif

enum ENUM_TYPE { consta, constb };
#undef ENUM_TYPE

...在此之后,您可以忘记解决方法,只需要一个操作员...

  operator E() const { return e;}

【讨论】:

  • 我决定使用它,因为它对其余代码库的干扰最小。
【解决方案2】:

将行改为

switch ((E)x) {

枚举和整数在编译器中非常相似(并且在内存中可能相同),因此同时拥有这两者会让人感到困惑。如果您专门铸造它,这里就不会有您想要使用的任何歧义。

【讨论】:

  • 我试图避免显式转换所有 switch 语句,这是我的最后一个选择:(
【解决方案3】:

您可以通过使用static_cast 自己选择转换来解决歧义:

switch(static_cast<E>(x))

另一种选择是创建一个或多个转换运算符explicit——这将通过限制编译器的选项来解决歧义。

但是,explicit 转换运算符仅适用于您的编译器不支持的 C++0x。

【讨论】:

  • explicit 转换是 C++0x 中的新功能。
  • @Jon explicit 关键字不适用于 gcc-4.3。抱怨只有构造函数可以是explicit
  • @nkarthiks:然后switch(static_cast&lt;E&gt;(x)) 会这样做。
  • @Jon:是的,但我试图将演员阵容作为最后的选择。看起来它是最兼容的解决方案。
  • @nkarthiks, @JasmesMcNellis:重新编辑——我自己应该考虑过explicit,但我对 GCC 支持的内容一点也不熟悉。
【解决方案4】:

C++ 是否不允许您自动从枚举转换为int,从而使operator int 变得不需要(例如,它会使用E 转换然后转换为int)?我知道你说你不想删除它,但你真的确认它破坏了 API 兼容性吗?

如果这不是一个选项,最好的办法可能是添加 as_intas_E 方法以在所需转换类型不明确的上下文中使用。

【讨论】:

    【解决方案5】:

    规范说明了条件(切换值):

    条件应为整数类型、枚举类型或存在单一转换函数到整数或枚举类型的类类型。

    您的类类型有 3 个转换为整数或枚举类型的函数,因此很容易违反此约束。如果您删除 operator int 重载,它甚至都不会工作,因为仍然有 2 个转换函数。不会发生重载决议。如果它不写任何东西,也不需要非常量 operator E 重载

    一个明确的演员将是一个安全的赌注。同样相当奇怪的方式是使用op+,但出于清楚的原因我不会采用这种方式

    switch (+x) { /* Don't do this in the wild */
      case consta: // ..
      case constb: // ..
    }   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多