Aroch
Почитай внимательней. Мы изучаем возможность инициализации членов туплы inplace, то есть без копирования или перемещения её членов. По аналогии с emplace в контейнерах. Здесь же ты явно создаешь экземпляры A, которые потом будут смещаться в туплу аа.
Went
> Почитай внимательней. Мы изучаем возможность инициализации членов туплы
> inplace, то есть без копирования или перемещения её членов. По аналогии с
> emplace в контейнерах. Здесь же ты явно создаешь экземпляры A, которые потом
> будут смещаться в туплу аа.
ок, не вопрос:
std::tuple<A, A> aa(std::make_tuple<A, A>( {1, 2}, {3}));
можешь и вовсе:
std::tuple<A, A> aa({1, 2}, {3});
осталось как-то Immobile проинициализировать
#include <tuple> struct Immobile { Immobile() = default; Immobile( const Immobile&) = delete; Immobile( Immobile&&) = delete; Immobile& operator=( const Immobile&) = delete; Immobile& operator=( Immobile&&) = delete; }; int main( ) { std::tuple<Immobile, int> t( ?, 10); }
вернее не делать этого
Идея - хранить поля как обычно, но в дополнение к ним дать одно из двух:
- мембер функцию field_refs, которая вернёт тьюпл из ссылок на все поля по очереди;
- статик функцию или константу на тьюпл из мембер-указателей на все поля по очереди.
Хотя сам тьюпл придётся всё-таки собирать вручную.
Aroch
> ок, не вопрос:
> std::tuple<A, A> aa(std::make_tuple<A, A>({1, 2}, {3}));
А разве здесь не будет копирования-перемещения экземпляров А внутри перемещаемой-копируемой туплы?
> можешь и вовсе:
> std::tuple<A, A> aa({1, 2}, {3});
Как я понимаю, мы сначала приводим {1, 2} к А (и {3} ко второй A), а потом вызываем обычный конструктор туплы с копированием-перемещением их вовнутрь оного.
#!
Да, вот тут как раз суть проблемы. Если конструктор не одного аргумента вызывать надо, то никак пока что не придумали.
Went
> не одного аргумента вызывать надо, то никак пока что не придумали
придумали {}, но ты уже развенчал это выше
в целом проще всего написать функцию сериализации для структуры, как делали лет 20 назад, можно выборочно указать что сериализовать, а что нет
struct S { Mem1 mem1; ... template <typename Arch> void serialize(Arch& ar) { ar & mem1; ... } };
не знаю, разве протобуф не то же самое генерит? что-то я уже запутался зачем вообще кортежи всплыли
Имбирная Ведьмочка
> - мембер функцию field_refs, которая вернёт тьюпл из ссылок на все поля по
> очереди;
Сработало на удивление гладко: https://godbolt.org/z/43MqGWTh4
Вариант с ссылками сразу на поля делать не стал - потому что в нём одну и ту же функцию придётся писать дважды, в конст- и нон-конст-варианте; тогда как поинтер-ту-мемберы - "полиморфны" относительно констности базового объекта.
tl;dr ключевого кода:
template<typename T, typename DT = decomposable_trait<T>> std::string decomposable_to_string(T const& t) { std::string buffer; bool is_first = true; for_each_tuple_element( DT::fields, [&]<typename F>( F T::* field_mptr) { if ( is_first) is_first = false; else buffer += " + "; buffer += ( t.*field_mptr).to_string( ); }); return buffer; } struct Foo { Bar<int> bi; Bar<float> bf; Bar<char> bc; Bar<Bar<bool>> bbb; Bar<bool> bb; std::string to_string( ) const { return decomposable_to_string( *this); } }; template<> struct decomposable_trait<Foo> { static constexpr auto fields = std::make_tuple( &Foo::bi, &Foo::bf, &Foo::bc, &Foo::bbb, &Foo::bb); };