将CRTP与reinterpret_cast一起放入目标类

时间:2018-04-30 20:06:37

标签: c++ language-lawyer c++17 crtp

背景

我喜欢在临时基础上应用外墙,而不是将它们烘焙到课堂本身。但我需要对数据进行操作,因此我需要从外观访问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。一段时间使用类似的东西,我不幸的是能够逃脱它。

问题

如何在Facade类中使用具有目标类类型的this

我对班级布局的理解

在对象内部的某个地方,以无序的方式,有数组和x_getter。通过reinterpret_cast,我试图欺骗它认为thiscoordinates,但当它执行operator[]时,使用的偏移是咬掉,离开物体,因此分裂。

1 个答案:

答案 0 :(得分:3)

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

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

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

通常,CRTP应在方法内使用static_cast

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

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