Размер структуры во время компиляции минус заполнение

Я пытаюсь использовать Boost MPL и Fusion для расчета размера структуры без учета каких-либо дополнений. Это моя текущая лучшая попытка:

Живой пример

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 работает, но только для структур с четырьмя полями.

Как я могу распространить это на произвольные структуры с большим или меньшим количеством полей?


person bhillam    schedule 02.06.2020    source источник
comment
How can I extend this to arbitrary structs? Что такое произвольные структуры? Вы имеете в виду, что для структур, не объявленных с использованием BOOST_FUSION? Вы не можете - С++ не имеет отражения.   -  person KamilCuk    schedule 02.06.2020
comment
На самом деле вы можете сделать это по крайней мере для AggregateTypes в C++14 и C++17. Идея в том, что вы можете посчитать макс. количество аргументов, которые вы можете передать в агрегатную инициализацию по умолчанию (SFINAE). Затем вы можете делегировать структурную декомпозицию, и у вас есть типы.   -  person lorro    schedule 02.06.2020
comment
@KamilCuk любая структура, адаптированная с помощью Boost Fusion, но с большим или меньшим количеством полей. Моя текущая реализация работает только для конкретного примера с четырьмя полями.   -  person bhillam    schedule 02.06.2020


Ответы (1)


Поскольку вы пометили этот код C++17, ответ таков: не используйте Boost.MPL. Учитывая даже С++ 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<T>() дает вам последовательность пар, где first является имя аксессора, а second — это функция, которая принимает объект и возвращает этот элемент).

Демо.

person Barry    schedule 02.06.2020
comment
это именно то, что я хотел, и гораздо более прямой, чем путь, по которому я шел. - person bhillam; 04.06.2020
comment
Что делать, если мой член структуры тоже является структурой, как мне вызвать рекурсивно sizeof_members? - person Reza; 18.08.2020