«Объединить» модули в один

#c #inheritance #reflection #structured-bindings #standard-layout

Вопрос:

Есть ли способ составить (или объединить, агрегировать) Стручки между ними ? Одно интуитивное решение:

 struct Base1 { int i; };
struct Base2 { char c; };

struct Derived : Base1, Base2 {};

// in a more generalized way
// template <class... Ts> struct Aggregate : Ts... {};
 

За исключением того, что мы кое-что теряем:

 int main()
{
    Derived d {42, 'c'}; // OK
    auto [i, c] = d; // Error
    static_assert(std::is_standard_layout_v<Derived>); // Error
}
 

Я вижу, что мы можем столкнуться с некоторыми двусмысленностями, конфликтами между объединенными базовыми классами. Но было бы довольно неплохо объединить стручки в один. Результат, которого я пытаюсь достичь:

 struct Expected { int i; char c; }; // I want Derived to behave exactly like this
 

Нахожусь ли я в царстве размышлений? Должен ли я в конечном итоге использовать макросы?

Комментарии:

1. Есть способы заставить это работать, написав свой собственный доступ к кортежу, но тип, который вы создаете, отличается нестандартной компоновкой

2. Вы хотели, чтобы результирующий агрегат также был модулем?

3. @Eljay На самом деле мне все равно, является ли полученная структура стручком или нет, она имеет тот же размер. Я бы, по крайней мере, реализовал функцию структурированных привязок. В общем виде, если возможно, то есть для template <class... Ts> struct Aggregate : Ts... {}; .

Ответ №1:

Если мы

не важно, является ли производная структура модулем или нет

, задача довольно проста Boost.PFR — просто преобразуйте свои модули в кортежи и объедините их:

 template<typename... Ts> using Merge = decltype(std::tuple_cat(
    boost::pfr::structure_to_tuple(std::declval<Ts>())...
));
 

Простой тест:

 int main() {
    struct Base1 { int i, j; };
    struct Base2 { char c; };
    using Expected = Merge<Base1, Base2>;
    static_assert(std::is_same_v<Expected, std::tuple<int, int, char>>);
    Expected expected{42, 1337, 'c'};
    autoamp;amp; [i, j, c] = expected;
}