You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何自定义Tuple大小超出预期?如何启用空基类优化?

问题原因

你的Tuple实现中,空类Nil是作为成员变量存储在Tuple<Nil>中的,这导致Tuple<Nil>不是空类——它包含一个Nil类型的成员,哪怕Nil是空类,该成员也会占据1字节(C++标准要求非空类的大小至少为1)。当Tuple<int*, Nil>继承自Tuple<Nil>时,基类的1字节加上自身int*的8字节,由于内存对齐要求(int*的对齐边界是8字节),总大小被填充到16字节,因此测试失败。

空基类优化(EBO)的核心生效条件是:基类必须是空类(无自身非静态数据成员、无虚函数/虚基类),且派生类的非静态成员类型与基类不同。你的实现中,空类被作为成员而非基类存储,因此无法触发EBO。

解决方案

调整Tuple的实现,将每个元素通过支持EBO的包装器存储为基类,而非成员。这样空类元素会被作为空基类处理,从而触发EBO优化。

修改后的完整代码如下:

#include <type_traits>
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

// 支持EBO的元素包装器
template <typename T, bool = std::is_empty_v<T> && !std::is_final_v<T>>
struct TupleElement : T {
    constexpr TupleElement(const T& val) : T(val) {}
    constexpr T& get() noexcept { return *this; }
    constexpr const T& get() const noexcept { return *this; }
};

// 非空类/基本类型,用成员存储
template <typename T>
struct TupleElement<T, false> {
    constexpr TupleElement(const T& val) : value(val) {}
    constexpr T& get() noexcept { return value; }
    constexpr const T& get() const noexcept { return value; }
private:
    T value;
};

// Tuple类模板实现
template <typename...> struct Tuple;

template <> struct Tuple<> {};

template <typename Head, typename... Tail>
struct Tuple<Head, Tail...> : Tuple<Tail...>, TupleElement<Head> {
    constexpr Tuple(const Head& head, const Tail&... tail)
        : Tuple<Tail...>(tail...), TupleElement<Head>(head) {}
};

struct Nil {};

TEST_CASE("test size")
{
    using T0 = Tuple<>;
    CHECK(sizeof(T0) == 1);

    using T1 = Tuple<double, std::string, int, char>;

    struct Foo
    {
        double d;
        std::string s;
        int i;
        char c;
    };

    CHECK(sizeof(T1) == sizeof(Foo));

    using T2 = Tuple<int*, Nil>;
    CHECK(sizeof(T2) == sizeof(int*));

    using T3 = Tuple<int*, Nil, Nil>;
    CHECK(sizeof(T3) == sizeof(int*));
}

说明

  1. TupleElement包装器:自动判断元素类型,空类直接继承(作为空基类),非空类/基本类型用成员存储,兼顾EBO优化和基本类型的存储需求。
  2. Tuple递归结构:每个Tuple<Head, Tail...>继承自Tuple<Tail...>和TupleElement<Head>,空类元素对应的TupleElement是空基类,触发EBO优化,其大小会被编译器完全忽略。
  3. 测试效果:Tuple<int*, Nil>和Tuple<int*, Nil, Nil>的大小会等于sizeof(int*),仅保留非空元素的大小(满足对齐要求)。

内容的提问来源于stack exchange,提问作者bobeff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:24:29