多个CRTP基的对齐类

Alignment of multiple CRTP base classes

在 CRTP 中,基础对象可以

在多重继承的情况下也是如此吗?第二个基址及以后的基址可能位于与派生对象不同的地址。考虑例如:

#include <iostream>
#include <string_view>

template<typename Derived>
struct Base1
{
    char c1;
};

template<typename Derived>
struct Base2
{
    char c2;
    auto& get2() const
    {
        return static_cast<const Derived&>(*this); // <-- OK?
    }
};

struct X : public Base1<X>, public Base2<X>
{
    X(std::string_view d) : data{d} {}

    std::string_view data;
};


int main()
{
    auto x = X{"cheesecake"};

    std::cout << x.get2().data << std::endl;
}

gcc 的未定义行为分析器says this is undefined behavior.
clang 的未定义行为分析器 detects no problem.

标准说的对吗?

更新:
gcc的bug目前已经在trunk上修复

是的,这个定义好了,你的代码就OK了。多重继承是铸造指针与原始指针不同的罕见情况。

如果你去源:

[expr.static.cast.11] A prvalue of type “pointer to cv1 B”, where B is a class type, can be converted to a prvalue of type “pointer to cv2 D”, where D is a complete class derived from B, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. ....

[expr.static.cast.2] An lvalue of type “cv1 B”, where B is a class type, can be cast to type “reference to cv2 D”, where D is a class derived from B, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. ...

这意味着您使用的转换是有效的,并且只要您不丢弃任何 cv 限定符,使用指针也同样有效。

据我所知,这是清理程序中的一个错误,在必须重定向时无法强制转换引用。

首先,这与CRTP无关。以下内容完全相同,CRTP 会自动为我们完成。

Base2<X>* base = &x;
const X* orig = static_cast<const X*>(base);

std::cout << &x << std::endl;
std::cout << base << std::endl;
std::cout << orig << std::endl;

输出:

0x7ffc7eeab4d0
0x7ffc7eeab4d1
0x7ffc7eeab4d0

这是正确的,gcc 的消毒剂不会抱怨任何事情。

但是如果你改变指向引用的指针:

X x{"cheesecake"};

Base2<X>& base = x;
const X& orig = static_cast<const X&>(base);//Line 36

std::cout << &x << std::endl;
std::cout << &base << std::endl;
std::cout << &orig << std::endl;

突然间你得到

0x7ffdbf87cf50
0x7ffdbf87cf51
0x7ffdbf87cf50

Program stderr

example.cpp:36:14: runtime error: reference binding to misaligned address 0x7ffdbf87cf51 for type 'const struct X', which requires 8 byte alignment
0x7ffdbf87cf51: note: pointer points here
 00 00 00  60 cf 87 bf fd 7f 00 00  0a 00 00 00 00 00 00 00  66 20 40 00 00 00 00 00  6d 19 40 00 00
              ^ 

意味着输出再次正确,但消毒剂在投回时错误地没有重定向引用。