Search code examples
c++c++17boost-hana

Compile size of a struct minus padding recusively


I have a similar Problem as in this question. I want to get the size of struct at compile time, including all the substructs without the compiler specific padding added.

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);

As I don't want to include the padding, I expect the size of the struct Foo to be 18 (including the size of the substruct Bar) but the code in the linked question does include the padding in the calculation and gives me a size of 19. The problem lies therein that the function should call bytesize recursively on all structs it encounters.

A minimal example which does not work as intended can be found here.


Solution

  • You have issue with returned types which are not what you expect (extra &&). std::decay_t fixes the issue:

    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