递归编译结构减去填充的大小

Compile size of a struct minus padding recusively

我遇到了与此 类似的问题。 我想在编译时获取结构的大小,包括所有未添加编译器特定填充的子结构。

struct Bar {
  BOOST_HANA_DEFINE_STRUCT(Bar,
      (std::uint8_t, a),
      (std::uint16_t, b)
   );
};

struct Foo {
  BOOST_HANA_DEFINE_STRUCT(Foo,
      (std::uint8_t, a),
      (std::uint16_t, b),
      (std::uint32_t, c),
      (std::uint64_t, d),
      (Bar, bar)
    );
};

template <typename T>
constexpr auto bytesize() -> size_t
{
 if constexpr (std::is_arithmetic<T>::value || std::is_enum<T>::value)
    return sizeof(T);
  else if constexpr (std::is_class<T>::value)
  {
    return hana::fold_left(
      hana::accessors<T>(), 0, [](auto total, auto member) {
        // I want to call bytesize recusively here:
        return bytesize<decltype(hana::second(member)(std::declval<T>()))>() + total;
      });
  }  
}

static_assert(bytesize<Foo>() == 18);

因为我不想包含填充,所以我希望结构 Foo 的大小为 18(包括子结构 Bar 的大小),但是链接中的代码问题确实在计算中包含了填充,并给出了 19 的大小。问题在于该函数应该在它遇到的所有结构上递归调用 bytesize。

可以找到一个没有按预期工作的最小示例 here

结构的大小比较多,因为有padding或者alignment.

https://en.wikipedia.org/wiki/Data_structure_alignment

gccclang 上,您可以使用 __attribute__((__packed__))

struct Bar {
  BOOST_HANA_DEFINE_STRUCT(Bar,
      (std::uint8_t, a),
      (std::uint16_t, b)
  );
} __attribute__((__packed__));

例子
https://godbolt.org/z/odMTEs

注意,在 x86 上,打包结构没有负面影响。至少不可测量。

在 Arm 上,它们也“足够快”地工作。

然而在其他一些架构上它们可能真的很慢甚至会“崩溃”CPU。

您对返回的类型有疑问,这不是您所期望的(额外 &&)。 std::decay_t 修复了问题:

return hana::fold_left(
    hana::accessors<T>(), 0, [](auto total, auto member) {
        using member_type = std::decay_t<decltype(hana::second(member)(std::declval<T>()))>;
        constexpr auto member_size = bytesize<member_type>();

        return total + member_size;
    });

Demo