Создание поднабора, начинающегося с std :: tuple & lt; some_types … & gt;

Давайте предположим, что std::tuple<some_types...> дано. Я хотел бы создать новый std::tuple чьи типы индексируются в [0, sizeof...(some_types) - 2], Например, предположим, что начальный кортеж std::tuple<int, double, bool>, Я хотел бы получить поднабор, определенный как std::tuple<int, double>,

Я совершенно новичок в вариационных шаблонах. В качестве первого шага я попытался написать struct отвечает за хранение различных типов оригинала std::tuple с целью создания нового кортежа такого же типа (как в std::tuple<decltype(old_tuple)> new_tuple).

template<typename... types>
struct type_list;

template<typename T, typename... types>
struct type_list<T, types...> : public type_list<types...>  {
typedef T type;
};template<typename T>
struct type_list<T> {
typedef T type;
};

То, что я хотел бы сделать, это что-то вроде:

std::tuple<type_list<bool, double, int>::type...> new_tuple // this won't work

И следующим шагом будет отбрасывание последнего элемента в пакете параметров. Как я могу получить доступ к нескольким typeхранится в type_list? и как отказаться от некоторых из них?

Благодарю.

4

Решение

Этот вид манипуляции довольно прост с техникой последовательности индексов: создайте последовательность индексов с двумя меньшими индексами, чем у вашего кортежа, и используйте эту последовательность для выбора полей из оригинала. С помощью std::make_index_sequence и вернуть тип вычета из C ++ 14:

template <typename... T, std::size_t... I>
auto subtuple_(const std::tuple<T...>& t, std::index_sequence<I...>) {
return std::make_tuple(std::get<I>(t)...);
}

template <int Trim, typename... T>
auto subtuple(const std::tuple<T...>& t) {
return subtuple_(t, std::make_index_sequence<sizeof...(T) - Trim>());
}

В C ++ 11:

#include <cstddef>     // for std::size_t

template<typename T, T... I>
struct integer_sequence {
using value_type = T;

static constexpr std::size_t size() noexcept {
return sizeof...(I);
}
};

namespace integer_sequence_detail {
template <typename, typename> struct concat;

template <typename T, T... A, T... B>
struct concat<integer_sequence<T, A...>, integer_sequence<T, B...>> {
typedef integer_sequence<T, A..., B...> type;
};

template <typename T, int First, int Count>
struct build_helper {
using type = typename concat<
typename build_helper<T, First,           Count/2>::type,
typename build_helper<T, First + Count/2, Count - Count/2>::type
>::type;
};

template <typename T, int First>
struct build_helper<T, First, 1> {
using type = integer_sequence<T, T(First)>;
};

template <typename T, int First>
struct build_helper<T, First, 0> {
using type = integer_sequence<T>;
};

template <typename T, T N>
using builder = typename build_helper<T, 0, N>::type;
} // namespace integer_sequence_detail

template <typename T, T N>
using make_integer_sequence = integer_sequence_detail::builder<T, N>;

template <std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;

template<size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;

#include <tuple>

template <typename... T, std::size_t... I>
auto subtuple_(const std::tuple<T...>& t, index_sequence<I...>)
-> decltype(std::make_tuple(std::get<I>(t)...))
{
return std::make_tuple(std::get<I>(t)...);
}

template <int Trim, typename... T>
auto subtuple(const std::tuple<T...>& t)
-> decltype(subtuple_(t, make_index_sequence<sizeof...(T) - Trim>()))
{
return subtuple_(t, make_index_sequence<sizeof...(T) - Trim>());
}

Жить в Колиру.

4

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

Вот способ решить вашу проблему напрямую.

template<unsigned...s> struct seq { typedef seq<s...> type; };
template<unsigned max, unsigned... s> struct make_seq:make_seq<max-1, max-1, s...> {};
template<unsigned...s> struct make_seq<0, s...>:seq<s...> {};

template<unsigned... s, typename Tuple>
auto extract_tuple( seq<s...>, Tuple& tup ) {
return std::make_tuple( std::get<s>(tup)... );
}

Вы можете использовать это следующим образом:

std::tuple< int, double, bool > my_tup;
auto short_tup = extract_tuple( make_seq<2>(), my_tup );
auto skip_2nd = extract_tuple( seq<0,2>(), my_tup );

и использовать decltype если вам нужен результирующий тип.

Совершенно другой подход будет писать append_type, который принимает тип и tuple<...>и добавляет этот тип в конец. Затем добавьте к type_list:

template<template<typename...>class target>
struct gather {
typedef typename type_list<types...>::template gather<target>::type parent_result;
typedef typename append< parent_result, T >::type type;
};

который дает вам возможность накапливать типы ваших type_list в произвольный пакет параметров, содержащий template, Но это не требуется для вашей проблемы.

5

Один из способов сделать это — рекурсивно передать два кортежа в вспомогательную структуру, которая берет первый элемент кортежа «source» и добавляет его в конец другого:

#include <iostream>
#include <tuple>
#include <type_traits>

namespace detail {

template<typename...>
struct truncate;

// this specialization does the majority of the work

template<typename... Head, typename T, typename... Tail>
struct truncate< std::tuple<Head...>, std::tuple<T, Tail...> > {
typedef typename
truncate< std::tuple<Head..., T>, std::tuple<Tail...> >::type type;
};

// this one stops the recursion when there's only
// one element left in the source tuple

template<typename... Head, typename T>
struct truncate< std::tuple<Head...>, std::tuple<T> > {
typedef std::tuple<Head...> type;
};
}

template<typename...>
struct tuple_truncate;

template<typename... Args>
struct tuple_truncate<std::tuple<Args...>> {

// initiate the recursion - we start with an empty tuple,
// with the source tuple on the right

typedef typename detail::truncate< std::tuple<>, std::tuple<Args...> >::type type;
};

int main()
{
typedef typename tuple_truncate< std::tuple<bool, double, int> >::type X;

// test
std::cout << std::is_same<X, std::tuple<bool, double>>::value; // 1, yay
}

Живой пример.

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