重载逻辑非运算符 vs bool 类型转换运算符

4

考虑以下代码:

class Truth
{
public:
    Truth(bool val) : value(val) {}
    bool operator!() {std::cout<<"operator!()"<<std::endl; return !value;}
    operator bool() {std::cout<<"operator bool()"<<std::endl; return value;}
private:
    bool value;
};

int main()
{
    Truth t(true);

    if(!t)
        std::cout<<"t is false"<<std::endl;
    else
        std::cout<<"t is true"<<std::endl;

    if(!!t)
        std::cout<<"t is false"<<std::endl;
    else
        std::cout<<"t is true"<<std::endl;

    if(t)
        std::cout<<"t is false"<<std::endl;
    else
        std::cout<<"t is true"<<std::endl;

    return 0;
}

在语句if(!t)if(!!t)中,会调用重载的operator!()实现,而在语句if(t)中则会调用重载的operator bool()实现(不出所料)。
然而,如果注释掉operator!()实现,在所有3个语句中将会调用operator bool()
我理解为什么会发生这种情况,但是我的担忧是,重载逻辑非运算符(!)似乎错过了一半的真值评估语义,而bool类型转换运算符则似乎很好地涵盖了这些语义。
我是否漏掉了什么或者应该鼓励使用bool类型转换而不是重载逻辑非运算符?

我明白你的意思,但是当 if (t) 没有 ! 时调用 operator! 也会令人困惑。 - chris
@chris,完全同意,这就是为什么我猜测应该不鼓励重载operator!。你觉得呢? - imreal
我不能说我能立刻想到任何有用的简单重载。我确定你可以在 Boost 中找到各种简单的重载,但这与每个运算符都是一样的。 - chris
1个回答

5
在C++11中,您可以简单地重载explicit operator bool()。除非您想要它执行不同的操作,否则没有必要重载operator! - 如果您认为需要这样做,那么您应该重新考虑一下。
从历史上看,重载operator bool会打开到任何数值类型的隐式转换的大门,这可能会导致混淆、歧义和微妙的错误;因此最好不要这样做。如果您不想陷入安全布尔习惯用语的困境中,重载operator!是一种简单的方式来允许在条件语句中使用,而不会打开那扇门。 (链接仅供历史参考;由于显式转换运算符,此惯用语已过时在C++11中已过时)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接