简体   繁体   English

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

[英]Odd behavior with operator>= overloading

I'm having a strange behavior with an operator overloading in C++. 我在C ++中有一个运算符重载的奇怪行为。 I have a class, and I need to check if its contents are greater or equal to a long double. 我有一个课程,我需要检查其内容是否大于或等于一个长整数。 I overloaded the >= operator to make this check, my declaration is as follows: 我重载了> =运算符以进行此检查,我的声明如下:

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

I have to say that I also have a cast-to-long-double operator for my class, that works without exceptions only under certain conditions. 我必须说,我的班级也有一个强制转换为双精度双精度运算符,该运算符仅在特定条件下才能正常工作。 Now, when I use this operator, the compiler complains that there's an ambiguous use of operator>= and the alternatives are: 现在,当我使用该运算符时,编译器会抱怨运算符> =的使用模棱两可,替代方法是:

  • Mine. 矿。
  • The built-in operator>=(long double, int) . 内置operator>=(long double, int)

Now, how do I force the program to use my operator? 现在,如何强制程序使用我的运算符?

2015 update: Or, if you want to keep conversion ability using the (double)obj syntax instead the obj.to_double() syntax, make the conversion function explicit by prefixing it with that keyword. 2015年更新:或者,如果您想使用(double)obj语法而不是obj.to_double()语法保持转换能力,请在该转换函数前添加该关键字作为前缀来使其explicit You need an explicit cast then for the conversion to trigger. 您需要显式强制转换,然后才能触发转换。 Personally, I prefer the .to_double syntax, unless the conversion would be to bool because in that case the conversion is used by if(obj) even if it is explicit , and that is considerably more readable than if(obj.to_bool()) in my opinion. 就我个人而言,我更喜欢.to_double语法,除非将转换转换为bool因为在那种情况下,即使if if(obj)explicit ,转换也被if(obj)使用,并且比if(obj.to_bool())更具可读性。在我看来。


Drop the conversion operator. 删除转换运算符。 It will cause troubles all the way. 它将一直引起麻烦。 Have a function like 具有像

to_double()

Or similar that returns the double value and call that function explicitly to get a double. 或类似的返回double值并显式调用该函数以获取double的函数。

For the problem at hand, there is this problem: 对于当前的问题,存在以下问题:

obj >= 10

Consider that expression. 考虑一下这种表达。 The builtin operator matches the first argument by a user defined conversion sequence for your type using the conversion operator long double(). 内置运算符使用转换运算符long double()为您的类型按用户定义的转换顺序匹配第一个参数。 But your function matches the second argument by a standard conversion sequence from int to long double (integral to floating point conversion). 但是您的函数通过从int到long double的标准转换序列(从整数到浮点转换)匹配第二个参数。 It is always ambiguous when there are conversions for two arguments, but not at least one argument that can be converted better while the remaining arguments are not converted worse for one call. 当有两个参数的转换时,它总是模棱两可的,但至少有一个参数可以更好地转换,而其余的参数在一次调用中转换得并不差。 In your case, the builtin one matches the second argument better but the first worse, but your function matches the first argument better but the second worse. 在您的情况下,内置参数与第二个参数的匹配较好,但第一个参数较差,但是您的函数与第一个参数的匹配较好,但第二个参数较差。

It's confusing, so here are some examples (conversions from char to int are called promotions, which are better than conversions from char to something other than int, which is called a conversion): 这很令人困惑,因此这里有一些示例(从char到int的转换称为提升,这比从char到int以外的其他转换(称为转换)要好):

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

Calls the first version. 调用第一个版本。 Because all arguments for the first can be converted better. 因为第一个参数可以更好地转换。 Equally, the following will still call the first: 同样,以下内容仍将称为第一个:

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

Because the first can be converted better, and the second is not converted worse. 因为第一个可以更好地转换,而第二个则不会更坏。 But the following is ambiguous : 但是以下内容不明确

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

It's more interesting in this case. 在这种情况下更有趣。 The first version accepts the first argument by an exact match. 第一个版本通过完全匹配接受第一个参数。 The second version accepts the second argument by an exact match. 第二个版本通过完全匹配接受第二个参数。 But both versions do not accept their other argument at least equally well. 但是,这两个版本都至少同样不能接受他们的其他论点。 The first version requires a conversion for its second argument, while the second version requires a promotion for its argument. 第一个版本的第二个参数需要转换,而第二个版本的其参数需要提升。 So, even though a promotion is better than a conversion, the call to the second version fails. 因此,即使升级比转换更好,对第二个版本的调用也会失败。

It's very similar to your case above. 这与上面的情况非常相似。 Even though a standard conversion sequence (converting from int/float/double to long double) is better than a user-defined conversion sequence (converting from MyClass to long double), your operator version is not chosen, because your other parameter (long double) requires a conversion from the argument which is worse than what the builtin operator needs for that argument (perfect match). 尽管标准转换序列(从int / float / double转换为long double)比用户定义的转换序列(从MyClass转换为long double) 更好 ,但由于您的其他参数(long double)仍未选择您的运算符版本)需要从参数进行转换,该转换比内置运算符对该参数所需的转换(完全匹配)差。

Overload resolution is a complex matter in C++, so one can impossibly remember all the subtle rules in it. 重载解析是C ++中的一件事,因此不可能记住其中的所有微妙规则。 But getting the rough plan is quite possible. 但是,制定粗略的计划是完全可能的。 I hope it helps you. 我希望它对你有所帮助。

By providing an implicit conversion to a double you are effectively stating, my class is equivalent to a double and for this reason you shouldn't really mind if the built in operator >= for double s is used. 通过有效地说明对double的隐式转换,您可以有效地说明这一点,我的类等效于double ,因此,您不必在意是否使用了double的内置运算符> =。 If you do care, then your class really isn't 'equivalent' to a double and you should consider not providing an implicit conversion to double , but instead providing an explicit GetAsDouble, or ConvertToDouble member function. 如果您确实关心的话,那么您的类实际上就不等同于double并且您应该考虑不提供对double隐式转换,而应提供显式的 GetAsDouble或ConvertToDouble成员函数。

The reason that you have an ambiguity at the moment is that for an expression t >= d where t is an instance of your class and d is a double, the compiler always has to provide a conversion of either the left hand side or the right hand side so the expression really is ambiguous. 您目前不清楚的原因是,对于表达式t >= d ,其中t是类的实例,而d是双精度型,编译器总是必须提供左侧或右侧的转换。如此一面手的表情确实是am昧的。 Either t 's operator double is called and the built-in operator >= for double s is used, or d must be promoted to a long double and your member operator >= is used. 要么调用toperator double ,然后使用针对double s的内置运算符> =,要么必须将d提升为long double然后使用成员运算符> =。

Edit, you've updated your question to suggest that your conversion is to long double and your comparison is against an int. 编辑,您已经更新了问题,建议您将转换为long double,并将比较与int进行比较。 In which case the last paragraph should read: 在这种情况下,最后一段应为:

The reason that you have an ambiguity at the moment is that for an expression t >= d where t is an instance of your class and d is an int , the compiler always has to provide a conversion of either the left hand side or the right hand side so the expression really is ambiguous. 您目前不清楚的原因是,对于表达式t >= d ,其中t是类的实例,而dint ,编译器始终必须提供左侧或右侧的转换。如此一面手的表情确实是am昧的。 Either t 's operator long double is called and the built-in operator >= for long double and int is used, or d must be promoted to a long double and your member operator >= is used. 要么调用toperator long double ,然后使用内置运算符> =来表示long doubleint ,要么必须将d提升为long double并使用成员运算符> =。

I assume you are comparing against a literal int , and not a long double : 我假设您正在与文字int进行比较,而不是long double int

MyClass o;

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

If that is the case both alternatives are as good/complex. 如果是这样的话,两种选择都一样好/复杂。

Using your operator long double() : 使用operator long double()

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

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

  1. built-in conversion int to long double 内置将int转换为long double
  2. MyClass::operator>=(long double)

You've got long double in the declaration. 您的声明中有long double Try changing it to double . 尝试将其更改为double

Your use of operator overloading combined with custom casting can be very confusing to users of your class. 将运算符重载与自定义强制转换结合使用会使类的用户非常困惑。 Ask yourself, would users of this class expect it to convert itself into a double, or be comparable with a double? 问问自己,此类用户希望它自己转换为双精度还是与双精度可比? Wouldn't having a .greaterThan(double) function achieve the same goal but without surprising the user? .greaterThan(double)函数不会实现相同的目标,但不会令用户感到惊讶吗?

I guess you could always explicitly cast your object to double before comparing, to avoid the ambiguity. 我猜想,在进行比较之前,您总是可以明确地将对象转换为两倍,以避免产生歧义。 But if I were you I'd reconsider the approach above and focus on writing code that's intuitive and behaves in an unsurprising manner, instead of fancy type-casting and operator overloading. 但是,如果您是我,我将重新考虑以上方法,并专注于编写直观且行为毫不奇怪的代码,而不是花哨的类型转换和运算符重载。

(Inspired by the FQA's wonderful rant about operator overloading ) (受到FQA 关于运算符重载的奇妙咆哮的启发)

  • The built-in operator>=(long double, int). 内置运算符> =(long double,int)。

Looks like you've defined: 看起来您已经定义了:

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

And you are missing: 而且您不见了:

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

So the compiler can't decide which way to convert. 因此,编译器无法确定转换方式。 (It's ambiguous.) (模棱两可。)

Perhaps a templated function (or method) would be helpful? 模板化的函数(或方法)也许会有所帮助?

Watch out for situations where a>=b invokes different methods than b>=a . 当心a> = b调用与b> = a不同的方法的情况

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

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