在 C++ 中重载运算符时,为什么 T* 优于 bool?

When overloading operators in C++ why is T* preferred over bool?

我有一个包装器 class,它的行为应该像一个指针。我已经超载了 operator T*operator bool。 Bool 做了一些额外的验证。 我尝试在 if 中使用该对象,但我注意到 operator T* 被调用而不是 bool。有人可以向我解释为什么吗?这是在标准中以某种方式指定的吗?我在 MSVC、clang 和 gcc 中测试了下面的示例代码,它们都调用了 operator T*。 此外,根据我在此页面上阅读的内容 (https://en.cppreference.com/w/cpp/language/implicit_conversion),if 应该尝试转换为 bool.

#include <stdio.h>

class MyClass
{
public:
    MyClass(int i)
        : m(i)
    {}

    operator bool() const
    {
        printf("operator bool()\n");
        return m;
    }

    operator int* ()
    {
        printf("operator int* ()\n");
        return &m;
    }

private:
    int m;
};

int main()
{
    MyClass a(5);
    MyClass b(0);

    if (a)
        printf("a is true\n");
    else
        printf("a is false\n");

    if (b)
        printf("b is true\n");
    else
        printf("b is false\n");

    return 0;
}

PS:我也试过 !!(bool),但它仍然调用 operator int*()。对于 operator bool(),我必须明确地调用它。

在您的 class 定义中,转换运算符 operator bool 是使用限定符 const 声明的,但 if 语句中使用的对象不是常量对象。

operator bool() const
                ^^^^^
{
    printf("operator bool()\n");
    return m;
}

删除限定符 const 将调用运算符 operator bool

或者像

那样声明转换运算符operator int *
operator const int* () const
{
    printf("operator int* ()\n");
    return &m;
}

然后将再次调用运算符 operator bool

当运算符具有限定符 const 并应用于非常量对象时,则需要再进行一次转换,即限定转换。

此外,您甚至可以将运算符声明为显式。例如

explicit operator bool() 
{
    printf("operator bool()\n");
    return m;
}

我想你可以在标准中找到具体的措辞。或者this proposal

但我会说你想要的是 explicit operator bool()

如果你想自己看看如何得出Vlad的(正确)答案,过程大致是

  1. if statement

    条件是一个表达式,可以根据上下文转换为 bool

  2. Contextual conversions 属于隐式转换 - 特别注意

    If there are multiple overloads of the function or operator being called, after the implicit conversion sequence is built from T1 to each available T2, overload resolution rules decide which overload is compiled.

    然后在转换顺序下,第三步"zero or one standard conversion sequence"在自定义转换之后,这一步可以将指针转换为bool。

    这意味着这两个用户定义的转换运算符对于该序列的中间步骤都是可行的。最后,

  3. Overload resolution

    描述了如何select最佳可行的功能。由于这两个运算符在转换序列的中间步骤的上下文中都是可行的,因此在 之后发生的额外的指针到布尔转换不会影响重载排名。

    具体来说,排名是基于这样一个事实:一个运算符需要对其隐式第一个 (this) 参数进行 const 限定,而另一个则不需要。这就是为什么同一运算符的一对 const 限定和非 const 限定的重载将始终选择其限定与调用对象最匹配的重载。