繁体   English   中英

运算符> =重载的奇怪行为

[英]Odd behavior with operator>= overloading

我在C ++中有一个运算符重载的奇怪行为。 我有一个课程,我需要检查其内容是否大于或等于一个长整数。 我重载了> =运算符以进行此检查,我的声明如下:

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

我必须说,我的班级也有一个强制转换为双精度双精度运算符,该运算符仅在特定条件下才能正常工作。 现在,当我使用该运算符时,编译器会抱怨运算符> =的使用模棱两可,替代方法是:

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

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

2015年更新:或者,如果您想使用(double)obj语法而不是obj.to_double()语法保持转换能力,请在该转换函数前添加该关键字作为前缀来使其explicit 您需要显式强制转换,然后才能触发转换。 就我个人而言,我更喜欢.to_double语法,除非将转换转换为bool因为在那种情况下,即使if if(obj)explicit ,转换也被if(obj)使用,并且比if(obj.to_bool())更具可读性。在我看来。


删除转换运算符。 它将一直引起麻烦。 具有像

to_double()

或类似的返回double值并显式调用该函数以获取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 ++中的一件事,因此不可能记住其中的所有微妙规则。 但是,制定粗略的计划是完全可能的。 我希望它对你有所帮助。

通过有效地说明对double的隐式转换,您可以有效地说明这一点,我的类等效于double ,因此,您不必在意是否使用了double的内置运算符> =。 如果您确实关心的话,那么您的类实际上就不等同于double并且您应该考虑不提供对double隐式转换,而应提供显式的 GetAsDouble或ConvertToDouble成员函数。

您目前不清楚的原因是,对于表达式t >= d ,其中t是类的实例,而d是双精度型,编译器总是必须提供左侧或右侧的转换。如此一面手的表情确实是am昧的。 要么调用toperator double ,然后使用针对double s的内置运算符> =,要么必须将d提升为long double然后使用成员运算符> =。

编辑,您已经更新了问题,建议您将转换为long double,并将比较与int进行比较。 在这种情况下,最后一段应为:

您目前不清楚的原因是,对于表达式t >= d ,其中t是类的实例,而dint ,编译器始终必须提供左侧或右侧的转换。如此一面手的表情确实是am昧的。 要么调用toperator long double ,然后使用内置运算符> =来表示long doubleint ,要么必须将d提升为long double并使用成员运算符> =。

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

MyClass o;

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

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

使用operator long double()

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

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

  1. 内置将int转换为long double
  2. MyClass::operator>=(long double)

您的声明中有long double 尝试将其更改为double

将运算符重载与自定义强制转换结合使用会使类的用户非常困惑。 问问自己,此类用户希望它自己转换为双精度还是与双精度可比? .greaterThan(double)函数不会实现相同的目标,但不会令用户感到惊讶吗?

我猜想,在进行比较之前,您总是可以明确地将对象转换为两倍,以避免产生歧义。 但是,如果您是我,我将重新考虑以上方法,并专注于编写直观且行为毫不奇怪的代码,而不是花哨的类型转换和运算符重载。

(受到FQA 关于运算符重载的奇妙咆哮的启发)

  • 内置运算符> =(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不同的方法的情况

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM