2

我在 C++ 中使用运算符重载时有一个奇怪的行为。我有一堂课,我需要检查它的内容是否大于或等于 long double。我重载了 >= 运算符来进行这个检查,我的声明如下:

bool MyClass::operator>=(long double value) const;

我不得不说,我的班级也有一个 cast-to-long-double 运算符,它仅在某些条件下无例外地工作。现在,当我使用此运算符时,编译器抱怨 operator>= 的使用不明确,替代方法是:

  • 矿。
  • 内置的operator>=(long double, int).

现在,我如何强制程序使用我的运算符?

4

6 回答 6

3

2015 更新:或者,如果您想使用(double)obj语法而不是语法来保持转换能力,请通过在其前面加上该关键字来obj.to_double()创建转换功能。explicit然后您需要显式转换才能触发转换。就个人而言,我更喜欢这种.to_double语法,除非转换是 to,bool因为在这种情况下,if(obj)即使它是explicit,也会使用转换,这比if(obj.to_bool())我认为的可读性要高得多。


删除转换运算符。一路上都会惹来麻烦。有一个像

to_double()

或类似的返回双精度值并显式调用该函数以获得双精度值。

对于手头的问题,有这个问题:

obj >= 10

考虑一下这个表达式。内置运算符使用转换运算符 long double() 通过用户定义的类型转换序列匹配第一个参数。但是您的函数通过从 int 到 long double(整数到浮点转换)的标准转换序列匹配第二个参数。当有两个参数的转换时总是模棱两可的,但至少有一个参数可以转换得更好,而其余的参数在一次调用中不会转换得更糟。在您的情况下,内置函数更好地匹配第二个参数,但第一个更差,但您的函数更好地匹配第一个参数,但第二个更差。

这很令人困惑,所以这里有一些示例(从 char 到 int 的转换称为提升,这比从 char 到非 int 的转换更好,这称为转换):

void f(int, int);
void f(long, long);
f('a', 'a');

调用第一个版本。因为第一个参数的所有参数都可以更好地转换。同样,以下仍将调用第一个:

void f(int, long);
void f(long, long);
f('a', 'a');

因为第一个可以转换得更好,而第二个不能转换得更差。但以下是模棱两可的:

void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous

在这种情况下更有趣。第一个版本通过完全匹配接受第一个参数。第二个版本通过完全匹配接受第二个参数。但是两个版本至少同样好地不接受他们的另一个论点。第一个版本需要对其第二个参数进行转换,而第二个版本需要对其参数进行提升。因此,即使促销比转换更好,对第二个版本的调用也会失败。

这与您上面的情况非常相似。即使标准转换序列(从 int/float/double 转换为 long double)比用户定义的转换序列(从 MyClass 转换为 long double)更好,但不会选择您的运算符版本,因为您的其他参数(long double ) 需要从参数进行转换,这比内置运算符对该参数的需要更差(完美匹配)。

重载解析在 C++ 中是一件复杂的事情,因此人们不可能记住其中的所有微妙规则。但是得到粗略的计划是很有可能的。我希望它对你有帮助。

于 2009-02-15T09:10:08.480 回答
3

通过提供对 a 的隐式转换,double您实际上是在说明,我的类等效于 a double,因此您不应该真正介意是否使用内置运算符 >= for doubles。如果您确实关心,那么您的类实际上并不“等效于” adouble并且您应该考虑不提供对 的隐式转换double,而是提供显式GetAsDouble 或 ConvertToDouble 成员函数。

您目前有歧义的原因是对于一个表达式t >= d,其中t是您的类的实例并且d是双精度,编译器总是必须提供左侧或右侧的转换,因此表达式真的是模棱两可的。要么调用t'soperator double并使用内置运算符 >= for doubles,要么必须将 d 提升为 along double并使用您的成员运算符 >=。

编辑,您已经更新了您的问题,表明您的转换是 long double 并且您的比较是针对 int 的。在这种情况下,最后一段应为:

你现在有歧义的原因是,对于一个表达式t >= dwhere tis 你的类的一个实例并且dis an int,编译器总是必须提供左侧或右侧的转换,所以表达式真的是模糊的。要么调用t'soperator long double并使用内置运算符 >= for long doubleand int,要么必须将 d 提升为 along double并使用您的成员运算符 >=。

于 2009-02-15T09:10:17.123 回答
1

我假设您正在与文字进行比较int,而不是long double

MyClass o;

if (o >= 42)
{
   // ...
}

如果是这种情况,两种选择都一样好/复杂。

使用你的operator long double()

  1. MyClass::operator long double()
  2. 内置operator>=(long double, int)

使用你的MyClass::operator>=(long double)

  1. 内置转换intlong double
  2. MyClass::operator>=(long double)
于 2009-02-15T09:12:05.293 回答
0

你已经long double在声明中了。尝试将其更改为double.

于 2009-02-15T09:03:11.867 回答
0

您将运算符重载与自定义转换结合使用可能会让您的类的用户非常困惑。问问自己,这个类的用户会期望它把自己转换成一个双精度数,还是可以与一个双精度数相媲美?有一个 .greaterThan(double) 函数不会达到相同的目标但不会让用户感到惊讶吗?

我想你总是可以在比较之前明确地将你的对象转换为 double,以避免歧义。但如果我是你,我会重新考虑上面的方法,并专注于编写直观且行为方式并不令人惊讶的代码,而不是花哨的类型转换和运算符重载。

(灵感来自 FQA关于运算符重载的精彩咆哮

于 2009-02-15T09:09:09.857 回答
0
  • 内置运算符>=(long double, int)。

看起来你已经定义了:

bool class::operator>=(long double value) { return value >= classValue; }

而你错过了:

bool class::operator>=(double value)      { return value >= classValue; }
bool class::operator>=(int value)         { return value >= classValue; }

所以编译器无法决定转换哪种方式。(这是模棱两可的。)

也许模板函数(或方法)会有所帮助?

注意a>=b调用与b>=a不同的方法的情况。

于 2009-02-15T16:10:04.023 回答