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

为何两种Tuple类模板实现内存占用不同?能否修复至相同大小?

可变参数Tuple模板与特化版本的内存差异问题

我实现了两种Tuple类模板——一种是针对不同参数数量的特化版本,另一种用可变参数模板实现。当把空类Nil作为元组的部分元素时,两种实现的内存占用不一样。为什么可变参数模板的第二种实现内存更大?能不能把它修复到和第一种一样的大小?

代码实现

#include <iostream>

using namespace std;

struct Nil {};

template <typename T1 = Nil, typename T2 = Nil>
struct Tuple1 : Tuple1<T2>
{
  T1 x;

  using Base = Tuple1<T2>;

  Base* base() { return static_cast<Base*>(this); }
  const Base* base() const { return static_cast<const Base*>(this); }

  Tuple1(const T1& t1, const T2& t2)
    : Base{ t2 }, x{ t1 } {}
};

template <> struct Tuple1<> {};

template <typename T1>
struct Tuple1<T1> : Tuple1<>
{
  T1 x;

  using Base = Tuple1<>;

  Base* base() { return static_cast<Base*>(this); }
  const Base* base() const { return static_cast<const Base*>(this); }

  Tuple1(const T1& t1)
    : Base{}, x{ t1 } {}
};

// ---------------------------------------------------------------------------

template <typename...> struct Tuple2;

template <> struct Tuple2<> {};

template <typename Head, typename... Tail>
struct Tuple2<Head, Tail...> : Tuple2<Tail...>
{
  Tuple2(const Head& head, const Tail&... tail)
    : Base{ tail... }, m_head{ head } {}

private:
  using Base = Tuple2<Tail...>;
  Head m_head;
};

int main()
{
  cout << "Tuple1 sizes:\n";
  cout << sizeof(Tuple1<>) << '\n';
  cout << sizeof(Tuple1<int*>) << '\n';
  cout << sizeof(Tuple1<int*, Nil>) << '\n';

  cout << '\n';

  cout << "Tuple2 sizes:\n";
  cout << sizeof(Tuple2<>) << '\n';
  cout << sizeof(Tuple2<int*>) << '\n';
  cout << sizeof(Tuple2<int*, Nil>) << '\n';

  return 0;
}

运行结果(MSVC 2022)

Tuple1 sizes:
1
8
8

Tuple2 sizes:
1
8
16

问题原因

  1. Tuple1的特化优化:Tuple1<int*, Nil>基于特化模板实现,它继承的Tuple1<Nil>虽然包含一个Nil成员,但MSVC对这种仅含空类成员的基类做了内存合并优化——将基类的1字节占用合并到派生类int*成员的对齐填充空间中,最终整个类的大小等于int*的大小(8字节)。
  2. Tuple2的布局与对齐:Tuple2<int*, Nil>的可变参数实现没有针对Nil做特殊处理,它继承的Tuple2<Nil>是一个包含Nil成员的类(大小1字节),再加上自身的int*成员(8字节)。由于内存对齐要求,Tuple2<Nil>的1字节会被填充到8字节,再加上int*的8字节,总大小被对齐到16字节。

修复方法

为Tuple2添加针对首参数为Nil的特化版本,当模板参数中出现Nil时,跳过该成员的存储,直接继承后续参数的Tuple2实例:

// 添加针对首参数为Nil的特化模板
template <typename... Tail>
struct Tuple2<Nil, Tail...> : Tuple2<Tail...>
{
    Tuple2(const Nil&, const Tail&... tail)
        : Tuple2<Tail...>(tail...) {}
};

修改后,Tuple2<int*, Nil>会直接继承Tuple2<int*>,而Tuple2<int*>的大小为8字节,因此Tuple2<int*, Nil>的大小也会变为8字节,与Tuple1<int*, Nil>一致。如果需要处理多个连续Nil的情况,可以继续添加更多特化,或者使用递归模板逻辑自动跳过所有Nil参数。

内容的提问来源于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 03:48:35