【问题标题】:C++ operator overloading resolution ambiguityC++ 运算符重载解析歧义
【发布时间】:2009-04-25 00:10:19
【问题描述】:

我正在尝试将一个古老的 C++ 代码库从 gcc 3.2 迁移到 gcc 4.1,因为我遇到了一些问题。在所有问题中,以下问题让我一无所知(我想我在 Java 上花了太多时间,或者我可能忘记了 C++ 的基础知识:-P)。

我有一个模板类

template < class T > class XVector < T >
{
   ...
   template < class T > T
   XVector < T >::getIncrement ()
   {
       ...
   }  
   template < class T > int
   XVector < T >::getValue (size_t index, T& value)
   {
      ...
      //The problematic line
      value = (T) (first_value + getIncrement())
                  * (long) (index - first_index);
      ....
   }
}

此类基于 STL std::vector。我有第二类 TypeValue,它的定义如下,它可以保存 int、long 及其无符号变体、float、double、std::string 之一。还重载了几乎所有可能的运算符。

class TypeValue
{
    union
    {
        long* _int_value;
        double* _real_value;
        string* _text_value;
    } _value;

    TypeValue();
    explicit TypeValue(long _long);
    explicit TypeValue(int _int);
    explicit TypeValue(unsigned long _ulong);
    ...
    //similarly for all the remaining supported types.
    TypeValue(const TypeValue& ) //Copy constructor

    virtual TypeValue& operator=(const TypeValue &rhs);
    TypeValue& operator+ (TypeValue& )const;
    TypeValue& operator* (TypeValue& )const;
    ...
    //For all the basic operators

    operator long() const;
    operator int() const;
    operator unsigned long() const;
    operator unsigned int() const;
    ...

}

最后我有了另一个类,我们称之为 build_breaker,它创建一个对象为XVector &lt; TypeValue &gt; a_variable;。现在,当我在 gcc 3.2 上编译它时,它编译没有任何问题。但是,当我尝试在 gcc 4.1 上编译它时,我收到错误消息,称 operator* 在类 XVector 中存在模棱两可的过载,而候选人是

运算符*(长整数,长整数) 运算符*(整数,长整数) 运算符*(长无符号整数,长整数) 运算符*(无符号整数,长整数) 运算符*(双精度整数) 运算符*(浮点数,长整数)

如果编译器说它在找到 T * long 的匹配项时遇到问题,那是有道理的,但是,它为什么要尝试将其类型转换为本机类型,然后执行算术运算? 请帮我解决这个问题。

提前致谢。

【问题讨论】:

  • 您的算术运算符应该接受并返回 const 引用,因为它们是 const 函数。你的赋值运算符应该接受一个 const 引用,但是让方法本身是 const 没有多大意义;它是一个赋值运算符,所以它应该修改你调用它的东西。
  • 稍微更正,赋值运算符声明为
     virtual TypeValue&amp; operator=(const SdmsTypedValue &amp;rhs); 
    不是纯虚,而是有方法定义。
  • 不要在 cmets 中“更正”它。通过编辑您的问题并使其正确来真正纠正它。当你这样做时,还请记住我们以前从未见过“SdmsTypedValue”;这是你第一次提到这种类型。
  • Rob,我已经更新了代码。对不起 SdmsTypedValue。这就是复制粘贴的效果。我想我需要提高我的代码审查技能。
  • Niel & Gorpik 认为发生了太多隐式转换并造成严重破坏。我进一步查看了代码,发现运算符 * 与 int 和 size_t 一起用作右侧类型。如果一种类型被重载,则其他引用在找到正确的调用时会遇到问题。所以我不得不为 RHS 上的所有类型重载 operator*。虽然它解决了问题,但我不确定这是否是这个问题的最佳解决方案。因为我没有其他开发人员追随我,对我的逻辑摸不着头脑。请提出建议。

标签: c++ templates gcc


【解决方案1】:

第二个操作数类型是long [int]。第一个是TypeValue,我预计,但是没有operator* 可以采用这两种确切的类型。但是,该运算符还有许多其他类型组合,编译器可以通过对第一个操作数进行隐式转换来选择它们。该语言允许编译器这样做以尝试找到匹配项。

但它应该选择众多转换中的哪一个?编译器无法选择int 是否优于long int。 (您可能会争辩说,由于第二个操作数是 long int,所以这应该是首选的转换目标,但事实并非如此。)

所以,一些建议:首先,不要提供这么多的隐式转换。由于该类只能容纳longdoublestring,因此我只提供这三个转换。仅此一项可能无法解决您的问题,但它可能会减少错误输出的大小并使其他事情更易于管理。

与其将(index - first_index) 转换为long 类型,不如考虑将其转换为T 类型(即TypeValue),因为这似乎是您真正想要执行的操作。

【讨论】:

  • 嗨 Rob,当我将 operator* 重载为 TypeValue& operator* (const long&) 时,编译器给了我,这个错误:ISO C++ 说这些是模棱两可的,即使第一个最差的转换优于第二个最差转换: 候选 1:TypeValue TypeValue::operator*(const long int&) 候选 2:operator*(float, size_t)
  • 我不建议为 operator* 提供 TypeValue-long 重载,是吗?提供更少的转换和更少的重载。您应该提供的唯一 operator* 是: > 这是一个接受 const 引用并返回值的 const 方法。 (不要返回引用。)然后,就像我之前说的,类型转换 (index - first_index) 为类型 T,此时编译器将从该差异构造一个 TypeValue 对象并将其与第一个 TypeValue 对象相乘你有。
【解决方案2】:

我会将所有转换运算符更改为命名函数,以便:

operator long() const;

变成

long ToLong() const;

通过强制转换运算符的隐式转换会导致各种问题,而我自己的编程标准禁止使用它们。

【讨论】:

    【解决方案3】:

    我们需要知道什么是 T。看起来您正在使用某种类型(例如 unsigned char,例如)实例化一个 XVector,该类型可以转换为您看到的所有类型,而编译器不知道哪个一个可供选择。

    【讨论】:

    • 在这种情况下,就很清楚了。 TypeValue 有很多隐式转换,编译器不知道该选择哪一个。事实上,我不明白这怎么可能在 gcc 3.2 下编译
    • 这段代码在 gcc 3.2.3 中编译没有错误或警告,这仍然让我很开心!
    猜你喜欢
    • 2021-05-02
    • 1970-01-01
    • 2010-09-27
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    相关资源
    最近更新 更多