这个typedef和转换运算符语法是什么意思?

3

我遇到了一个包装boost::shared_ptr的类,但我不太理解转换操作符是什么以及它的具体工作方式。该类如下:

class TestWrapper {
public:
    explicit TestWrapper(int* ptr) : internal(ptr) {}


    typedef boost::shared_ptr<int> TestWrapper::* safe_bool;

    boost::shared_ptr<int> internal;

    bool operator!() { return !internal; }
    operator safe_bool() const { return internal ? &TestWrapper::internal : 0; }
};

该代码使得像下面这样的测试可以像测试包装指针的null性一样工作:

TestWrapper t(new int(5));

if(!t) {
    std::cout << "!null" << std::endl;
}

if(t) {
    std::cout << "null" << std::endl;
}

然而,我无法理解typedef的含义:
typedef boost::shared_ptr<int> TestWrapper::* safe_bool;

它看起来不像是boost::shared_ptr的重命名,也不像函数指针(需要括号?)。那这是什么?

我也无法弄清楚转换运算符的含义:

operator safe_bool() const { return internal ? &TestWrapper::internal : 0; }

&TestWrapper::internal是什么?为什么它与typedef相同类型?为什么0可以转换成它?


成员函数指针。C++库程序员确实需要使用英勇的语法来避免指向布尔值的隐式转换设计错误。这是你自己永远不会做的事情,直到你收到足够多的“你的代码烂透了”的错误报告。Boost的人们非常英勇。 - Hans Passant
在C++11中,有 explicit operator bool(),因此不再需要这个小技巧了。请查看https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool。 - tmlen
转换运算符的作用类似于 operator bool(),因此 if(t) 起作用。但是,operator bool() 也允许其他操作,例如将 TestWrapper 隐式转换为 int。因此,使用数据成员指针类型 safe_bool,因为它可以在 if 中使用,但不能进行其他任何操作(没有隐式转换、没有 < 比较等)。 - tmlen
1个回答

4
boost::shared_ptr<int> TestWrapper::*

这是一个类数据成员指针。它指向一个来自类TestWrapper的类型为boost::shared_ptr<int>的数据成员。

我们举一个更简单的例子,关于类数据成员指针:

int X::*

这是指向类 X 的数据成员类型为 int 的类数据成员指针,因此你可以执行以下操作:

struct X
{
    int a;
    int b;
    float c;
};

struct Y
{
    int a;
};

auto test()
{
    using T = int X::*; // a pointer to an int data member of class X

    X x1{1, 2};
    X x2{100, 200};

    T pa = &X::a;       // pointer to data member a of class X
    T pb = &X::b;       // pointer to data member b of class X

    T pc = &X::c;  // illegal
    T py = &Y::a;  // illegal

    std::cout << x1.*pa; // 1
    std::cout << x1.*pb; // 2

    std::cout << x2.*pa; // 100
    std::cout << x2.*pb; // 200

}

operator safe_bool() const

这是一种将提到的类数据成员指针类型转换的运算符。

&TestWrapper::internal 是什么?

&TestWrapper::internal 是类 TestWrapper 的数据成员 internal 的地址。

为什么它和 typedef 相同?

因为 internal 是类 TestWrapper 的类型为 boost::shared_ptr<int> 的数据成员。

为什么可以将 0 转换为它?

作为指针,您可以将 nullptr 分配给它。或者,正如代码所做的那样,您可以将 0 分配给它。此运算符仅在 (bool) internal != false 时返回指向数据成员 internal 的指针,否则返回空指针。


太棒了,谢谢。我已经写了13年的C++,以前从未见过指向数据成员的语法。现在感觉更有意义了。 - Collin

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