reinterpret_cast 的 CRTP 进入目标 class

CRTP with reinterpret_cast into target class

背景

我希望临时应用外观,而不是将它们烘焙到 class 本身。但是我需要对数据进行操作,所以我需要 this 可以从外观访问。这是一个小例子:

#include <array>
#include <iostream>

template <typename T>
struct x_getter
{
    friend T;

    double x() const
    {
        return (*real_self)[0];
    }

    void x(double new_x)
    {
        (*real_self)[0] = new_x;
    }

private:
    T* real_self = reinterpret_cast<T*>(this);
    x_getter() = default; //prevents accidental creation
};

struct coordinates : std::array<double, 3>, x_getter<coordinates>
{
    using std::array<double, 3>::array;
};


int main()
{
    coordinates origin{};
    std::cout << origin.x();
    origin.x(12.7);
    std::cout << ' ' << origin.x() << '\n';
}

It segfaults。前一段时间使用类似的东西,我很不幸能够逃脱它。

问题

如何使目标类型 class 的 this 在外观 class 中可用?

我对class布局的理解

在对象内部某处,以无序的方式,有数组和x_getter。通过 reinterpret_casting 它,我试图欺骗它认为 thiscoordinates,但是当它执行 operator[] 时,使用的偏移量有点偏离,它超出了对象,因此出现段错误。

这里的问题是 reinterpret_cast 不起作用,因为 this 指针不指向 coordinates 的开头 class 因为它继承自 array 在继承 x_getter 之前。此 class 的内存布局如下所示:

coordinates
|- std::array<double, 3>
|- x_getter

当你使用reinterpret_cast<T*>(this)时,存储在this指针中的地址是x_getter对象的地址,但你强制编译器假定它实际上是[=14]的地址=] 对象。因此,取消引用这样一个指向派生 class 的指针会导致各种未定义的行为。

通常 CRTP 应该在方法内部使用 static_cast:

double x() const
{
    return (*static_cast<TDerived const *>(this))[0];
}

reinterpret_cast 不同,static_cast 会正确调整 this 指针以正确指向派生对象。