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.");
在这种情况下,最后一个断言失败,因为元组实际上大于 4 个字节。有没有办法在不破坏类层次结构的情况下避免这种情况?或者我是否必须实现我自己的配对实现以其他方式针对这种情况进行优化?
最佳答案
空对象必须占用一些空间的原因是两个不同的对象必须具有不同的地址。异常(exception)情况是派生类型的基类子对象可以与派生的完整对象具有相同的地址(如果派生类型的第一个非静态成员与基类 [*] 的类型不同) . 空基优化利用它来删除任意添加到空基的额外空间,以确保对于任何完整对象 sizeof x!=0
。
在您的例子中,元组包含两个 A
子对象,一个是C
的基类,另一个是 的基类>B
,但它们不同,因此它们必须具有不同的地址。这两个对象都不是另一个的基础子对象,因此它们不能具有相同的地址。您甚至不需要使用 std::tuple
来查看此效果,只需创建另一种类型即可:
struct D : B, C {};
D
的大小将严格大于 B
和 C
的大小。要检查实际上有两个 A
子对象,您可以尝试向上转换为指向 A
的指针,编译器会很乐意向您吐出一些歧义错误。
[*] 出于同样的原因,标准也明确禁止这种情况:
struct A {};
struct B : A { A a; };
同样,在这种情况下,在每个 B
类型的完整对象中,有两个 A
对象,它们必须具有不同的地址。
关于c++ - 公共(public)基类打破了元组的空基类优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15076961/