c++重载运算符 bool() 给出了一个含糊不清的重载错误:operator+

发布于 2024-10-22 22:29:25 字数 1413 浏览 2 评论 0原文

我正在编译 MegaInt 类的一些 C++ 代码,该类是一个正十进制类型类,允许对大数进行算术运算。

我想重载运算符 bool 以允许这样的代码:

MegaInt m(45646578676547676);  
if(m)  
    cout << "YaY!" << endl;

这就是我所做的:

header:

class MegaInt
{
    public:
        ...
    operator bool() const;
};

const MegaInt operator+(const MegaInt & left, const MegaInt & right);
const MegaInt operator*(const MegaInt & left, const MegaInt & right);

implementation:

MegaInt::operator bool() const
{
    return *this != 0;
}
const MegaInt operator+(const MegaInt & left, const MegaInt & right)
{
    MegaInt ret = left;
    ret += right;
    return ret;
}

现在,问题是如果我这样做:

MegaInt(3424324234234342) + 5;

它给了我这个错误:

“operator+(const MegaInt&, const MegaInt&)”中“operator+”的重载不明确 注意:候选者是:operator+(int, int) | 注意: const MegaInt 运算符+(const MegaInt&, const MegaInt&)|

我不知道为什么。重载的 bool() 是如何导致operator+变得不明确的?¸

谢谢。


好吧,每个人都给了我很好的答案,不幸的是,他们似乎都没有完全解决我的问题。

void* 或 Safe Bool Idiom 都可以。除了一个小问题外,我希望有一个解决方法:

与 0 比较时,例如:

if (aMegaInt == 0)

编译器再次给出不明确的重载错误。我明白为什么:它不知道我们是在与 false 还是与值为 0 的 MegaInt 进行比较。尽管如此,在这种情况下,我希望它转换为 MegaInt(0)。有没有办法强制这个?

再次感谢您。

I'm compiling some c++ code of a class MegaInt which is a positive decimal type class that allows arithmetic operations on huge numbers.

I want to overload operator bool to allow code like this:

MegaInt m(45646578676547676);  
if(m)  
    cout << "YaY!" << endl;

This is what I did:

header:

class MegaInt
{
    public:
        ...
    operator bool() const;
};

const MegaInt operator+(const MegaInt & left, const MegaInt & right);
const MegaInt operator*(const MegaInt & left, const MegaInt & right);

implementation:

MegaInt::operator bool() const
{
    return *this != 0;
}
const MegaInt operator+(const MegaInt & left, const MegaInt & right)
{
    MegaInt ret = left;
    ret += right;
    return ret;
}

Now, the problem is if I do:

MegaInt(3424324234234342) + 5;

It gives me this error:

ambiguous overload for 'operator+' in 'operator+(const MegaInt&, const MegaInt&)
note: candidates are: operator+(int, int) |
note: const MegaInt operator+(const MegaInt&, const MegaInt&)|

I don't know why. How is the overloaded bool() causing operator+ to become ambiguous?¸

Thank You.


Well, everyone gave me great answers, unfortunately, none of them seem to solve my problem entirely.

Both void* or the Safe Bool Idiom works. Except for one tiny problem, I hope has a workaround:

When comparing with 0 like:

if (aMegaInt == 0)

The compiler gives an ambiguous overload error again. I understand why: it doesn't know if we're comparing to false or to MegaInt of value 0. None the less, in that case, I'd want it to cast to MegaInt(0). Is there a way to force this?

Thank You Again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

以往的大感动 2024-10-29 22:29:25

C++ 编译器可以自动将 bool 转换为 int,这就是它在这里要做的事情。

解决这个问题的方法是使用safe bool idiom

从技术上讲,创建 operator void* 不是安全 bool 习惯用法的示例,但在实践中它足够安全,因为您遇到的 bool/int 问题是一个常见的错误,并且弄乱了一些完全合理且正确的代码(正如您从问题中看到的那样),但是 void* 转换的误用并不常见。

The C++ compiler is allowed to automatically convert bool into int for you, and that's what it wants to do here.

The way to solve this problem is to employ the safe bool idiom.

Technically, creating an operator void* is not an example of the safe bool idiom, but it's safe enough in practice, because the bool/int problem you're running into is a common error, and messes up some perfectly reasonable and otherwise correct code (as you see from your question), but misuses of the void* conversion are not so common.

不乱于心 2024-10-29 22:29:25

维基百科条目关于C++0x 的显式转换运算符有一个不错的总结为什么您会在 C++0x 之前看到此错误。基本上,bool 转换运算符是整型转换类型,因此它将用在整型算术表达式中。 C++0x 之前的修复是使用 void * 作为转换运算符; void * 可以转换为布尔表达式,但不能转换为整数表达式。

The wikipedia entry on explicit conversion operators for C++0x has a decent summary of why you see this error pre-C++0x. Basically, the bool conversion operator is an integral conversion type, so it will be used in an integral arithmetic expression. The pre-C++0x fix is to instead use void * as the conversion operator; void * can be converted to a boolean expression, but not to an integral expression.

南城追梦 2024-10-29 22:29:25

正如 Erik 的回答所述,这里的问题是,通过提供到 bool隐式转换,您为可以表示多种含义的表达式打开了大门;在这种情况下,编译器会抱怨不明确并给出错误。

但是,请注意,提供到 void*隐式转换不会让您摆脱困境;它只会改变出现问题的表达式集。

对于此问题,有两种无懈可击的解决方案:

  • 显式转换为 bool(如果该类表示具有直观“真/假”值的实体,则这可能是不可取的)
  • 使用 safe bool idiom (这确实涵盖了所有基础,但生活中有很多美好的事物,而 C++ 太复杂了 - - 你付出代价)

As Erik's answer states, the problem here is that by providing an implicit conversion to bool you are opening the door to expressions that can mean multiple things; in this case the compiler will complain of ambiguity and give your an error.

However, note that providing an implicit conversion to void* will not let you off the hook; it will just change the set of expressions which present a problem.

There are two airtight solutions to this issue:

  • Make the conversion to bool explicit (which can be undesirable if the class represents an entity with an intuitive "true/false" value)
  • Use the safe bool idiom (this really covers all bases, but as many good things in life and C++ is way too complicated -- you pay the price)
雨夜星沙 2024-10-29 22:29:25

问题是 bool 可以自由转换为 int。因此,表达式 MegaInt(3424324234234342) + 5; 可以同样有效地解释为:

(bool)(MegaInt(3424324234234342)) + 5;

或者:

MegaInt(3424324234234342) + MegaInt(5);

这些表达式中的每一个都涉及一个用户定义的转换,并且在编译器看来是相等的。由于这个原因,转换为 bool 是非常有问题的。如果能有一种方法来表明它只应该发生在明确需要 bool 的上下文中,那就太好了,但事实并非如此。 :-/

其他人建议的转换为 void * 是一种解决方法,但我认为作为一种解决方法,它有自己的问题,我不会这样做。

The problem is that bool can freely convert to int. So the expression MegaInt(3424324234234342) + 5; can equally validly be interpreted this way:

(bool)(MegaInt(3424324234234342)) + 5;

or:

MegaInt(3424324234234342) + MegaInt(5);

Each one of those expressions involves one user defined conversion and are equal in the eyes of the compiler. Conversion to bool is highly problematic for this reason. It would be really nice to have a way to say it should only happen in a context that explicitly requires a bool, but there isn't. :-/

The conversion to void * that someone else suggests is a workaround, but I think as a workaround it has problems of its own and I wouldn't do it.

玩套路吗 2024-10-29 22:29:25
MegaInt(3424324234234342) + 5;

MegaInt + int;

编译器应该将您的 MegaInt 转换为整数(bool 是整数类型)还是将整数转换为 MegaInt(您有一个 int 构造函数)?

您可以通过创建 operator void * 而不是 operator bool 来解决此问题:

operator void *() const { return (*this != 0) ? ((void *) 1) : ((void *) 0); }

MegaInt(3424324234234342) + 5;

MegaInt + int;

Should the compiler convert your MegaInt to an integral (bool is an integral type) or the integer to MegaInt (you have an int constructor)?

You fix this by creating an operator void * instead of an operator bool:

operator void *() const { return (*this != 0) ? ((void *) 1) : ((void *) 0); }

七分※倦醒 2024-10-29 22:29:25

其他人提到了 Safe Bool 习语。然而,对于像你这样的对象,当你想要完整的代数支持时,添加所有这些令人讨厌的特殊逻辑是一个坏主意。

您正在定义自定义整数类型。通过定义“operator==”和“operator!=”,然后实现“operator bool()”,您可以得到更多的成果:

operator bool()
{
   return (*this != 0);
}

仅从这 3 个函数中,您就可以获得整数的所有“if”惯用语,对于您的自定义整数,它们的行为与内置整数相同:“if(a==b)”、“if(a!=b)”、“if(a)”、“if(!a” )”。你隐含的“bool”规则也将(如果你小心的话)直观地工作。

此外,完整的“Safe Bool Idiom”是不必要的。想想看 - 您唯一需要它的时候是“1)2个对象的比较定义不明确或未定义,2)强制转换为(int)或其他原始类型需要保护,3)对象有效性定义明确(返回布尔值的实际来源)。”

好吧,如果您确实希望支持转换为 int 或 float 等数字类型,则 2) 只是一个考虑因素。但是对于没有明确定义的相等概念的对象(#1),提供这样的强制转换不可避免地会产生“if(a==b)”逻辑炸弹的风险,该习惯用法应该可以保护您免受这种风险。只需声明“operator int()”和这样的私有,就像对不可复制对象上的复制构造函数所做的那样,然后就可以完成它:

class MyClass {
private:
   MyClass(const MyClass&);
   operator int();
   operator long();
   // float(), double(), etc. ...
public:
   // ctor & dtor ..
   bool operator==(const MyClass& other) const { //check for equality logic... }
   bool operator!=(const MyClass& other) const { return !(*this == other); }
   operator bool() { return (*this != 0); }
};

Others have mentioned the Safe Bool Idiom. However, for objects like yours it is a bad idea to add all this nasty, special logic when you want full algebra support anyway.

You're defining a custom integer type. You get far more for your effort by defining "operator==" and "operator!=", then implementing "operator bool()" as something like:

operator bool()
{
   return (*this != 0);
}

Just from those 3 functions you get all of the "if" idioms for integers, and they'll behave the same for your custom ints as the built-in ones: "if(a==b)", "if(a!=b)", "if(a)", "if(!a)". Your implicit "bool" rule will also (if you're careful) work intuitively as well.

Besides, the full "Safe Bool Idiom" is unnecessary. Think about it- the only time you need it is "1) comparison of 2 objects is ill-defined or undefined, 2) cast to (int) or other primitive types needs to be protected and 3) object validity IS well-defined (the actual source of the returned bool)."

Well, 2) is only a consideration if you actually wish to SUPPORT casting to a numeric type like int or float. But for objects that have NO well-defined notion of equality (# 1), providing such casts unavoidably creates the risk of the very "if(a==b)" logic bombs the idiom supposedly protects you from. Just declare "operator int()" and such private like you do with the copy ctor on non-copyable objects and be done with it:

class MyClass {
private:
   MyClass(const MyClass&);
   operator int();
   operator long();
   // float(), double(), etc. ...
public:
   // ctor & dtor ..
   bool operator==(const MyClass& other) const { //check for equality logic... }
   bool operator!=(const MyClass& other) const { return !(*this == other); }
   operator bool() { return (*this != 0); }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文