在C++中重载运算符时,为什么T*比bool更受青睐?

6
我有一个包装类,应该像指针一样运作。我重载了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(),我必须显式地调用它。


1
在链接中跳转到“安全布尔问题”部分。 - Richard Critten
3个回答

7
在您的类定义中,类型转换运算符 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;
}

3
详细说明:非const成员函数在重载决议中胜出,因为它需要比const成员函数更少的转换。 - Kerrek SB
@VladfromMoscow 非常感谢您的快速回复和澄清!“当运算符具有const限定符并应用于非常量对象时,需要进行一种称为资格转换的转换。”这就是我之前所缺少的 :) - Radu C
@RaduC 这个转换应用于隐式参数 this。 - Vlad from Moscow

3
如果您想看到如何自己得出弗拉德的(正确)答案,大致过程如下。
  1. if语句

    条件是一个表达式,该表达式在上下文中可以转换为bool类型。

  2. 上下文转换属于隐式转换 - 特别注意的是

    如果被调用的函数或运算符有多个重载,在从T1到每个可用的T2建立隐式转换序列之后,重载解析规则决定编译哪个重载。

    然后在转换顺序下,第三步"零个或一个标准转换序列"在用户定义的转换之后进行,并且此步骤可以将指针转换为bool类型。

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

  3. 重载解析

    描述如何选择最佳可行函数。由于两个运算符在转换序列的中间步骤的上下文中都是可行的,因此发生在此之后的额外指针到bool的转换不会对重载排名产生贡献。

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


-5

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

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


1
请阅读如何撰写一个好的回答? - Daniel Langr

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