Распаковка двух пакетов параметров путем объединения их элементов в пары типов - PullRequest
2 голосов
/ 08 июня 2019

Учитывая, например, N определенные пользователем типы, я бы хотел, чтобы функция возвращала std::tuple длины N, где каждый элемент создается с помощью вызова функции некоторой функции (примером которой является func ниже) :

#include <tuple>
#include <utility>

template <typename T> 
T func(int x)
{
    return T();
}

template<typename... T, std::size_t... I> 
std::tuple<T...> build_tuple()
{
    // How do I write this in a generic way?
    return std::make_tuple(
        func<std::string>(0),
        func<int>(1),
        func<int>(2)
        );

    // This won't work, obviously
    // return std::make_tuple(func<T...>(I...));
}

int main() 
{
    build_tuple<std::string, int, int>();
}

По сути, мой вопрос заключается в том, как мне распаковать аргументы, чтобы получить что-то вроде «type0, 0», «type1, 1» и т. Д. Вместо «type0, type1, ..., 0, 1,. .. ", если это имеет смысл.

Это похоже на общую проблему, есть ли идиоматическое решение?

1 Ответ

3 голосов
/ 08 июня 2019

Если size_t аргументы 0, 1, ..., вы можете просто использовать дополнительный уровень косвенности:

template<class Tuple, std::size_t... I> 
Tuple build_tuple_impl(std::index_sequence<I...>)
{
    return std::make_tuple(
        func<std::tuple_element_t<I, Tuple>>(I)...);
}

template<typename... Ts> 
auto build_tuple()
{
    using Tuple = std::tuple<Ts...>;
    return build_tuple_impl<Tuple>(std::make_index_sequence<sizeof...(Ts)>{});
}

// Usage:
auto t = build_tuple<std::string, int, int>();

Более общий случай:

template<class Tuple, std::size_t... Is, std::size_t... I> 
Tuple build_tuple_impl(std::index_sequence<Is...>, std::index_sequence<I...>)
{
    constexpr std::size_t is[] = {Is...};
    return std::make_tuple(
        func<std::tuple_element_t<I, Tuple>>(is[I])...);
}

template<typename... Ts, std::size_t... Is>
auto build_tuple(std::index_sequence<Is...> is)
{
    static_assert(sizeof...(Ts) == sizeof...(Is));

    using Tuple = std::tuple<Ts...>;
    return build_tuple_impl<Tuple>(is, std::make_index_sequence<sizeof...(Ts)>{});
}

// Usage:
auto t = build_tuple<std::string, int, int>(std::index_sequence<3, 4, 5>{});

Не то, чтобы вы не могли написать build_tuple<std::string, int, int, 3, 4, 5>(). Одна из последовательностей должна быть упакована в один тип.

...