【问题标题】:more than one operator matches these operands多个运算符匹配这些操作数
【发布时间】:2011-08-24 22:04:39
【问题描述】:

假设我们有下一个代码:

struct int64
{
    long long value;

    int64() : value(0) {}
    int64(signed char i8) : value(i8) {}
    int64(unsigned char u8) : value(u8) {}
    int64(short i16) : value(i16) {}
    int64(unsigned short u16) : value(u16) {}
    int64(int i32) : value(i32) {}
    int64(unsigned u32) : value(u32) {}
    int64(long long i64) : value(i64) {}
    int64(unsigned long long u64) : value(u64) {}
    int64(const int64& i64) : value(i64.value) {}

    int64& operator+=(const int64& rhs) { return value += rhs.value, *this; }
    int64& operator-=(const int64& rhs) { return value -= rhs.value, *this; }

    friend int64 operator+(const int64& lhs, const int64& rhs) { return int64(lhs) += rhs; }
    friend int64 operator-(const int64& lhs, const int64& rhs) { return int64(lhs) -= rhs; }

    operator  char() const { return (char)value;  }
    operator short() const { return (short)value; }
    operator int() const { return (int)value; }
    operator long long() const { return value; }
};

编译这段代码时:

int64 q = 500;
int64 m = q + 1024;

由于1024q 到整数类型有4 个类似的转换可用,所以发生错误,为了解决这个问题,我从int64 中删除了operator XX 并添加了以下代码:

template <typename n>
operator n() const { return (n)value; }

现在我可以执行以下代码:

int64 q = 500;
int64 m = q + 1024;
short r = q;

模板定义适用于 Visual C++GCC 编译器,但适用于 Intel C++ 编译器。

如何编写适用于这些编译器的转换运算符?

【问题讨论】:

    标签: c++


    【解决方案1】:

    您应该为您支持的所有类型编写operator+ 定义:

    int64 operator+(int num) {
        return int64(value + num);
    }
    
    int64 operator+(short num) {
        ...
    }
    
    ...
    

    您将 int 添加到 int64 并将结果分配给 int64 但它没有复制构造函数,因此它将其转换为某种整数类型并尝试对所有内容进行一些奇怪的处理那些转换运算符和构造函数。

    【讨论】:

    • @Ben 你不是通过定义一个来放弃编译器生成的(至少是复制 ctor)吗?
    • 如果您定义任何其他构造函数,而不是复制 ctor 或赋值运算符,您将失去编译器生成的默认构造函数。
    • 有一个复制构造函数,编译器生成的赋值运算符就可以了,这不是问题。对象 q 可以转换为整数类型,数字 1024 也可以转换为 int64 类型,这是造成歧义的原因。
    • @Ben 啊,我当时印象错了。
    • @Muhammad 也许你认为你“不应该”,但你有没有试过看看它是否能解决你的错误?
    【解决方案2】:

    这里的问题是,如果你同时提供一个内置类型的构造函数和一个转换运算符到同一类型,然后有一个包含这两种类型的表达式,C++ 就不能真正优先考虑它应该采用的方式去。因此,“myInt64Variable + 1024”可以通过转换为 int 运算符表示“(int)myInt64Variable + 1024)”,或者通过构造函数表示“myInt64Variable + (int64)1024”。

    根据我的经验,处理此问题的最佳方法是不提供转换运算符,或者如果您必须拥有它们,则创建一个 toInt() 函数或类似函数。从您的自定义类型到内置类型的任何转换都将是有损的,否则为什么要使用自定义类型?并且在人们执行有损转换时让人们注意到是一件好事。

    【讨论】:

      【解决方案3】:

      从 C++11 开始(在问这个问题时它刚刚被批准),您可以标记转换explicit

      struct int64
      {
          // ...
      
          explicit operator  char() const { return (char)value;  }
          explicit operator short() const { return (short)value; }
          explicit operator int() const { return (int)value; }
          explicit operator long long() const { return value; }
      };
      

      这应该适用于所有主要编译器的最新版本(我测试过的所有编译器都有足够的 C++11 支持)。如果您愿意,您也可以将其应用于您的模板化转换运算符,尽管我更喜欢四种非模板化转换(另外,这会使我尝试使用的 ICC 版本崩溃!):

      struct int64
      {
          // ...
      
          template <typename n>
          explicit operator n() const { return static_cast<n>(value); }
      };
      

      但是,这意味着您不能使用short r = q;。对我来说,这是一件好事,因为缩小转换确实应该是

      short r = static_cast<short>(q);
      

      【讨论】:

        猜你喜欢
        • 2020-05-20
        • 2013-04-21
        • 2012-05-07
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多