Определение порядка инициализации элемента при создании std :: tuple

Я хотел бы сохранить значения инициализации для элементов в кортеже внутри отдельного кортежа, чтобы я мог использовать те же значения, что и в качестве предустановки для других кортежей соответствующего типа.

Для моей программы очень важно, чтобы конструкторы элементов кортежа вызывались в порядке слева направо (в противном случае это в лучшем случае оказалось бы очень запутанным).

Вот упрощенная версия моей программы:

#include <tuple>

// Elements are the end points of a Widget hierarchy
struct Element
{
using initer_t = int;
Element( const initer_t pIniter )
:data{ pIniter }
{
printf("Creating %i\n", data);
}
const initer_t data;
};

// A Widget class stores any number of Elements and/or other Widget instances
template<typename... Elems>
struct Widget
{
using initer_t = std::tuple<typename Elems::initer_t...>;
Widget( const initer_t pIniter )
:elements{ pIniter }
{}
const std::tuple<Elems...> elements;
};

int main()
{
using Button = Widget<Element, Element>;
using ButtonList = Widget<Button, Button, Element>;

Button::initer_t basic_button_initer{ 0, 1 }; // presets for Buttons
Button::initer_t other_button_initer{ 2, 3 };

ButtonList::initer_t buttonlist_initer{ basic_button_initer, other_button_initer, 4 }; //a preset for a ButtonList

ButtonList buttonlist{ buttonlist_initer };
return 0;
}

Итак, я инициализирую std::tuple<Elems...> elements член Widget<Elems...> с std::tuple<typename Elems::initer_t...> в Widget<Elems...>список инициализации конструктора.
Это должно инициализировать каждый элемент elements с соответствующим значением инициализации типа, определенного initer_t используя значения в pIniter.
initer_t тип — это тип для каждого члена иерархии виджетов (например, Widget<typename...> или Element), который является типом, с которым должен быть инициализирован элемент иерархии.
Но порядок, в котором это происходит, справа налево, а мне нужно слева направо.

Выход программы

Creating 4
Creating 3
Creating 2
Creating 1
Creating 0

Но я хочу изменить этот порядок.

Как я могу сделать это в этом случае?

0

Решение

В стандарте нет требования для заказа std::tuple Я боюсь, инициализация члена.

Вы можете перебрать tuple в определенном порядке, например:

#include <tuple>
#include <iostream>

#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>

int main()
{
auto a = std::make_tuple(true, 42, 3.14, "abc");
boost::fusion::for_each(a, [](auto& value) {
std::cout << value << '\n';
});
}

Выходы:

1
42
3.14
abc
2

Другие решения

Для тех, кто заинтересован в решении, я нашел способ контролировать порядок инициализации и сохранять постоянство elements:

#include <tuple>

template<typename... Elems>
struct construct
{
template<size_t... Ns, typename Head, typename... Rest>
static constexpr const std::tuple<Rest...>
drop_head_impl( const std::index_sequence<Ns...> ns,
const std::tuple<Head, Rest...> tup )
{
return std::tuple<Rest...>( std::get<Ns + 1u>( tup )... );
}

template<typename Head, typename... Rest>
static constexpr const std::tuple<Rest...>
drop_head( const std::tuple<Head, Rest...> tup )
{
return drop_head_impl( std::make_index_sequence<sizeof...(Rest)>(), tup );
}

template<typename Head>
static constexpr const std::tuple<Head>
func_impl( const std::tuple<typename Head::initer_t> initer )
{
return  std::tuple<Head>( { std::get<0>( initer ) } );
}

template<typename Head, typename Next, typename... Rest>
static constexpr const std::tuple<Head, Next, Rest...>
func_impl( const std::tuple<typename Head::initer_t, typename Next::initer_t, typename Rest::initer_t...> initer )
{
std::tuple<Head> head( { std::get<0>( initer ) } );
return std::tuple_cat( head, func_impl<Next, Rest...>( drop_head(initer) ) );
}

static constexpr const std::tuple<Elems...>
func( const std::tuple<typename Elems::initer_t...> initer )
{
return func_impl<Elems...>( initer );
}
};

// Elements are the end points of a Widget hierarchy
struct Element
{
using initer_t = int;
Element( const initer_t pIniter )
:data{ pIniter }
{
printf( "Creating %i\n", data );
}
const initer_t data;
};

// A Widget class stores any number of Elements and/or other Widget instances
template<typename... Elems>
struct Widget
{
using initer_t = std::tuple<typename Elems::initer_t...>;
Widget( const initer_t pIniter )
:elements( construct<Elems...>::func( pIniter ) )
{}
const std::tuple<Elems...> elements;
};

int main()
{
using Button = Widget<Element, Element>;
using ButtonList = Widget<Button, Button, Element>;

Button::initer_t basic_button_initer{ 0, 1 }; // presets for Buttons
Button::initer_t other_button_initer{ 2, 3 };

ButtonList::initer_t buttonlist_initer{ basic_button_initer, other_button_initer, 4 }; //a preset for a ButtonList

ButtonList buttonlist{ buttonlist_initer };
return 0;
}

construct структура принимает кортеж initer_ts (initer), создает кортеж, содержащий первый элемент Elems... используя первый элемент инициатора, затем удаляет первый элемент инициатора и передает оставшийся кортеж себе, что вызывает кортеж со следующим элементом Elems... быть построенным с использованием следующего элемента в initer. Эта рекурсия остановлена ​​перегрузкой func_impl для кортежа с одним элементом, который просто создает этот элемент из его initer_t в кортеже и возвращает его. Этот одноэлементный кортеж соединяется с кортежем с предыдущим элементом, результат возвращается на более высокий уровень и там объединяется с одноэлементным кортежем и так далее.

1

По вопросам рекламы [email protected]