Аргументы конструктора из кортежа

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

В почти C ++ 11 код:

template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return T(get<0>(args), get<1>(args), ...); }
};

Как можно ... в вызове конструктора заполняться без фиксации длины?

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

6

Решение

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

Самый простой способ реализовать диспетчеризацию аргумента — использовать расширение пакета для выражений, которые содержат упакованные последовательность целых чисел во время компиляции. Механизм шаблонов необходим для построения такой последовательности (см. Также примечание в конце этого ответа для получения дополнительной информации о предложении стандартизировать такую ​​последовательность).

Предположим, есть класс (шаблон) index_range который инкапсулирует диапазон времени компиляции целых чисел [M, N) и класс (шаблон) index_list который инкапсулирует список целых чисел во время компиляции, вот как бы вы их использовали:

template<typename T, typename... Args>
struct foo
{
tuple<Args...> args;

// Allows deducing an index list argument pack
template<size_t... Is>
T gen(index_list<Is...> const&)
{
return T(get<Is>(args)...); // This is the core of the mechanism
}

T gen()
{
return gen(
index_range<0, sizeof...(Args)>() // Builds an index list
);
}
};

И вот возможная реализация index_range а также index_list:

//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS

// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};

// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
// Declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;

// Base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};

// Induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{
};
}

// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;

Также обратите внимание, что интересное предложение от Джонатан Уэйкли существует для стандартизировать int_seq шаблон класса, который очень похож на то, что я назвал index_list Вот.

5

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

C ++ 14 добавит стандартную поддержку index_sequence:

template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
template <size_t... Indices>
T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};
3

Вам нужно будет использовать трюк с индексами, что означает слой косвенности:

template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<typename T, typename... Args>
struct foo {
tuple<Args...> args;
T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
template<std::size_t... Is>
T gen(indices<Is...>) { return T(get<Is>(args)...); }
};
1

Создайте последовательность индексов от 0 до n-1:

template<size_t... indexes>
struct seq {};

template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};

template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
typedef seq<indexes...> type;
};

распакуйте их параллельно с вашими аргументами или как указатель get<> в твоем случае.

Цель что-то вроде:

template< typename T, typename Tuple, typename Indexes >
struct repack;

template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
T operator()( tuple<Ts...> const& args ) const {
return T( get<indexes>(args)... );
}
};

использование repack в вашем gen как это:

T gen() {
repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
return repacker( args );
}
1
По вопросам рекламы [email protected]