c ++重载运算符bool()使用operator +给出了一个模糊的重载错误

时间:2011-03-15 02:00:24

标签: c++ operator-overloading boolean

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

我想重载operator bool以允许这样的代码:

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

这就是我所做的:

头:

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

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

实现:

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 +'在'operator +'中的模糊重载(const MegaInt&amp;,const MegaInt&amp;)   注意:候选者是:operator +(int,int)|   注意:const MegaInt运算符+(const MegaInt&amp;,const MegaInt&amp;)|

我不知道为什么。如何导致操作符+的重载bool()变得模糊不清?¸

谢谢。


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

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

与0比较时:

if (aMegaInt == 0)

编译器再次出现模糊的重载错误。我理解为什么:它不知道我们是在比较假,还是在比较值为0的MegaInt。尽管如此,在这种情况下,我希望它转换为MegaInt(0)。有没有办法强迫这个?

再次感谢你。

6 个答案:

答案 0 :(得分:12)

允许C ++编译器自动将bool转换为int,这就是它想要做的事情。

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

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

答案 1 :(得分:3)

explicit conversion operators for C++0x上的维基百科条目对您在C ++ 0x之前看到此错误的原因有一个很好的总结。基本上,bool转换运算符是一个完整的转换类型,因此它将用于整数算术表达式。前C ++ 0x修复程序将使用void *作为转换运算符; void *可以转换为布尔表达式,但不能转换为整数表达式。

答案 2 :(得分:2)

正如Erik的回答所述,这里的问题是通过向bool提供隐式转换,你打开了表达可能意味着多种事物的表达的大门;在这种情况下,编译器会抱怨含糊不清并给出错误。

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

这个问题有两个不透明的解决方案:

  • 明确转换为bool(如果类表示具有直观“true / false”值的实体,则可能不合适)
  • 使用safe bool idiom(这真的涵盖了所有基础,但生活中的许多好东西和C ++太复杂了 - 你需要付出代价)

答案 3 :(得分:1)

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

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

或:

MegaInt(3424324234234342) + MegaInt(5);

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

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

答案 4 :(得分:0)

MegaInt(3424324234234342) + 5;

MegaInt + int;

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

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

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

答案 5 :(得分:0)

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

您正在定义自定义整数类型。通过定义“operator ==”和“operator!=”,然后将“operator bool()”实现为:

,您可以获得更多的努力。
operator bool()
{
   return (*this != 0);
}

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

此外,完整的“安全布尔成语”是不必要的。想一想 - 你需要它的唯一时间是“1)2个对象的比较是错误定义的或未定义的,2)转换为(int)或其他原始类型需要保护3)对象有效性是明确定义的(返回布尔的实际来源)。“

嗯,2)只是一个考虑,如果你真的希望支持转换为数字类型,如int或float。但是对于那些没有明确定义的平等概念的对象(#1),提供这样的演员阵容不可避免地会产生非常“if(a == b)”逻辑炸弹的风险,这些成语可能会保护你。只需声明“operator int()”和私有就像你在不可复制对象上复制ctor那样私有并完成它:

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); }
};