Как мне сгенерировать рекурсивные структуры данных на шаблонах с переменными числами?

Я пытаюсь понять технику рекурсивная генерация структуры данных используя TMP с этим вопросом.

Вопрос

Предположим, у меня есть вариационный шаблон template<typename... Ts> struct my_sets { };,

В my_sets Я хотел бы создать новый тип, чьи данные зависят от Ts,

Например, я хочу my_sets иметь один std::set<T> элемент данных для каждого элемента / типа, который находится в Ts...

using x_t = my_sets<int,char,std::string>;
x_t x;

x.insert<0>(   5   );  // into a std::set<int> member in my_sets<>
x.insert<1>(  'z'  );  // into a std::set<char> member in my_sets<>
x.insert<2>( "foo" );  // into a std::set<std::string> member in my_sets<>

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

Между прочим, если проще реализовать мутатор через перегрузку свободной функции или простой функции, это тоже нормально:

insert<0>( x,   5   );  // into a std::set<int> member in my_sets<>
insert<1>( x,  'z'  );  // into a std::set<char> member in my_sets<>
insert<2>( x, "foo" );  // into a std::set<std::string> member in my_sets<>

4

Решение

Что случилось с std::tuple Вот?

#include <tuple>
#include <set>

template<class... Ts>
using my_sets = std::tuple<std::set<Ts>...>;

// ...

auto x = my_sets<int, char, std::string>;

std::get<0>(x).insert(5);
std::get<1>(x).insert('z');
std::get<2>(x).insert("foo");

Для внешности добавьте бесплатный insert функция:

#include <utility>

template<std::size_t I, class SetTuple, class Arg>
auto insert(SetTuple& st, Arg&& arg)
-> decltype(std::get<I>(st).insert(std::forward<Arg>(arg)))
{
return std::get<I>(st).insert(std::forward<Arg>(arg));
}
12

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

@Xeo предлагает элегантное и простое решение. Если вы хотите иметь insert<> однако в качестве функции-члена вы можете использовать следующий подход:

#include <set>
#include <tuple>

template<typename... Ts>
struct my_sets : protected std::set<Ts>...
{
using types = std::tuple<Ts...>;

template<int I, typename T>
typename std::pair<
typename std::set<typename std::tuple_element<I, types>::type>::iterator,
bool> insert(T&& t)
{
return std::set<typename std::tuple_element<I, types>::type>::insert(
std::forward<T>(t)
);
}

// ...

// Function for retrieving each set...
template<int I>
typename std::set<typename std::tuple_element<I, types>::type>& get()
{
return *this;
}
};

И вот как бы вы это использовали

#include <string>

int main()
{
my_sets<int, double, std::string> s;
s.insert<0>(42);
s.insert<1>(3.14);
s.insert<2>("Hello World!");

s.get<0>().insert(42);
}

Обратите внимание, что вышеупомянутое решение не допускает множественные вхождения одного и того же типа в списке типов (что может или не может быть желательным), хотя его можно легко расширить, чтобы разрешить их:

#include <set>
#include <tuple>

namespace detail
{
template<int... Is>
struct indices
{
typedef indices<Is..., sizeof...(Is)> next;
};

template<int I>
struct index_range
{
using type = typename index_range<I - 1>::type::next;
};

template<>
struct index_range<0>
{
using type = indices<>;
};

template<int I, typename T>
struct dummy : T { };

template<typename, typename... Ts>
struct my_sets { };

template<int... Is, typename... Ts>
struct my_sets<indices<Is...>, Ts...> : protected dummy<Is, std::set<Ts>>...
{
using types = std::tuple<Ts...>;

template<int I, typename T>
typename std::pair<
typename std::set<typename std::tuple_element<I, types>::type>::iterator,
bool
> insert(T&& t)
{
return dummy<I, std::set<typename std::tuple_element<I, types>::type>>::
insert(std::forward<T>(t));
}

template<int I>
dummy<I, std::set<typename std::tuple_element<I, types>::type>>& get()
{
return *this;
}
};
}

template<typename... Ts>
using my_sets = detail::my_sets<
typename detail::index_range<sizeof...(Ts)>::type,
Ts...
>;

И вот как вы бы это использовали:

#include <string>

int main()
{
my_sets<int, double, int, std::string> s;

s.insert<0>(42);
s.insert<1>(3.14);
s.insert<2>(1729);
s.insert<3>("Hello World!");

s.get<0>().insert(42);
}
2

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