公共基类打破了元组的空基类优化

MvG*_*MvG 3 c++ gcc libstdc++ c++11 stdtuple

gcc 4.7.1对元组进行空基类优化,我认为这是一个非常有用的功能.但是,似乎有一个意外的限制:

#include <tuple>
#include <cstdint>
#include <type_traits>
class A { };
class B : public A { std::uint32_t v_; };
class C : public A { };
static_assert(sizeof(B) == 4,                "A has 32 bits.");
static_assert(std::is_empty<C>::value,       "B is empty.");
static_assert(sizeof(std::tuple<B, C>) == 4, "C should be 32 bits.");
Run Code Online (Sandbox Code Playgroud)

在这种情况下,最后一个断言失败,因为元组实际上大于4个字节.有没有办法避免这种情况,而不打破类层次结构?或者我是否必须实现我自己的对实现,以其他方式优化这种情况?

Dav*_*eas 6

空对象必须占用一些空间的原因是两个不同的对象必须具有不同的地址.例外的是,一个派生类型的基子对象可以具有相同的地址作为派生完整的对象(如果派生类型的第一非静态成员是不一样的类型为基准的[*] .该空base optimization使用它来删除任意添加到空基的额外空间,以确保sizeof x!=0任何完整的对象.

在你的情况下,元组持有两个 A子对象,一个是C另一个的基础B,但它们是不同的,因此它们必须具有不同的地址.这两个对象都不是另一个的基础子对象,因此它们不能具有相同的地址.您甚至不需要使用std::tuple来查看此效果,只需创建另一种类型:

struct D : B, C {};
Run Code Online (Sandbox Code Playgroud)

的大小D将严格比两者的尺寸更大BC.要检查实际上有两个A子对象,您可以尝试向上转换指针,A编译器很乐意在您的方向上吐出一些模糊错误.

[*]该标准也明确禁止此案,原因相同:

struct A {};
struct B : A { A a; };
Run Code Online (Sandbox Code Playgroud)

同样,在这种情况下,在每个完整的类型对象中B,有两个A对象,它们必须具有不同的地址.