【问题标题】:Compile-time Size of Struct Minus Padding结构减去填充的编译时大小
【发布时间】:2020-06-02 09:34:38
【问题描述】:

我正在尝试使用 Boost MPL 和 Fusion 来计算不包括任何填充的结构的大小。这是我目前最好的尝试:

Live example

template<class T>
constexpr std::size_t sizeof_members(void)
{
    using namespace std;
    namespace mpl = boost::mpl;
    namespace fusion = boost::fusion;

    //This works, but only for structs containing exactly 4 members...
    typedef typename mpl::apply<mpl::unpack_args<mpl::vector<mpl::_1, mpl::_2, mpl::_3, mpl::_4>::type >, T>::type member_types;

    typedef typename mpl::transform<member_types, mpl::sizeof_<mpl::_1> >::type member_sizes;
    typedef typename mpl::accumulate<member_sizes, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type sum;
    return sum();
}

BOOST_FUSION_DEFINE_STRUCT(
    (), Foo_t,
    (std::uint8_t,  a)
    (std::uint16_t, b)
    (std::uint32_t, c)
    (std::uint64_t, d)
);
static_assert(sizeof_members<struct Foo_t>() == 15);

int main()
{
    std::cout << "sizeof_members = " << sizeof_members<struct Foo_t>() << std::endl;
    std::cout << "sizeof = " << sizeof(struct Foo_t) << std::endl;

    return 0;
}

预期输出:

sizeof_members<struct Foo_t>() = 15
sizeof(struct Foo_t) = 16

我可以将类型序列转换为包含每种类型大小的整数序列,并且可以计算该序列的总和,但是在将结构转换为序列的第一步时遇到了麻烦类型。 Fusion 文档说BOOST_FUSION_DEFINE_STRUCT 生成样板来定义和调整任意结构作为随机访问序列的模型,我认为它应该与 mpl::transform 兼容,但是我似乎缺少一些胶水代码使这项工作。我目前使用 mpl::unpack_args 的方法有效,但仅适用于具有四个字段的结构。

如何将其扩展到具有更多或更少字段的任意结构?

【问题讨论】:

  • How can I extend this to arbitrary structs? 什么是“任意结构”?您的意思是,对于未使用 BOOST_FUSION 声明的结构?你不能——C++ 没有反射。
  • 其实,你至少可以对 C++14 和 C++17 中的 AggregateTypes 做到这一点。这个想法是,你可以计算最大值。您可以传递给默认聚合初始化 (SFINAE) 的参数数量。然后你可以委托给一个结构分解,你就有了类型。
  • @KamilCuk 任何适应 Boost Fusion 但具有更多或更少字段的结构。我当前的实现仅适用于具有四个字段的特定示例。

标签: c++ c++17 boost-mpl compile-time-constant boost-fusion


【解决方案1】:

既然你标记了这个 C++17,答案是:不要使用 Boost.MPL。即使给定 C++11,您想要的元编程库也是 Boost.Mp11 - 它在所有方面都好得多。

您想使用的更新、更易于使用、编译时间效率更高的 Boost.Fusion 版本是 Boost.Hana

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

而你想使用 Boost.Hana 的原因是因为sizeof_members(对于任意数量的成员)可以写成:

template <typename T>
constexpr auto sizeof_members() -> size_t
{
    return hana::fold(hana::accessors<T>(), size_t{},
        [](size_t s, auto mem){
            return s + sizeof(hana::second(mem)(std::declval<T>()));
        });
}

static_assert(sizeof_members<Foo_t>() == 15);

这读起来和你真正想做的完全一样:你想折叠所有的成员,从 0 开始,用一个累加函数来增加下一个成员的大小(accessors&lt;T&gt;() 给你一个序列对其中first 是访问器的名称,second 是一个接受对象并返回该成员的函数。

Demo.

【讨论】:

  • 这正是我想要的,而且比我前进的道路更直接。
  • 我的struct成员也是struct怎么办,如何递归调用sizeof_members?
猜你喜欢
  • 1970-01-01
  • 2014-05-22
  • 2016-09-18
  • 2012-08-22
  • 2020-07-26
  • 1970-01-01
  • 2013-03-07
  • 1970-01-01
  • 2018-10-28
相关资源
最近更新 更多