Преобразовать тип кортежа в другой тип кортежа - PullRequest
1 голос
/ 09 апреля 2020

Предположим, у меня есть тип кортежа std::tuple<x,y,z> или, может быть, std::tuple<a,b>. Я хотел бы использовать универсальный способ преобразования типов в моем кортеже, например "functionize", чтобы получить

std::tuple<std::function<void(x)>,
           std::function<void(y)>,
           std::function<void(z)>>

или, возможно, получить хранилище для shared_pointers, например

std::tuple<std::shared_pointer<a>,
           std::shared_pointer<b>>

Как бы я достичь этого с C ++ 17? Ответы C ++ 20 интересны, но не применимы в моей текущей ситуации.

Мотивация : у меня есть класс, который будет параметризован списком произвольных и не обязательно уникальных типов, и хотел бы иметь член std :: function для каждого типа в списке.

1 Ответ

5 голосов
/ 09 апреля 2020

Специализация шаблона - это, вероятно, самый простой способ.

template <typename T>
struct functionize;

template <typename... Ts>
struct functionize<std::tuple<Ts...>> {
    using type = std::tuple<std::function<void(Ts)>...>;
}

using MyTuple = std::tuple<int, double, char>;
using MyTupleFunctionized = typename functionize<MyTuple>::type;

Чтобы сделать его более обобщенным c, вы можете принять параметр шаблона шаблона для применения к пакету.

template <typename Tuple, template <typename> typename Component>
struct transform_tuple;

template <typename... Ts, template <typename> typename Component>
struct transform_tuple<std::tuple<Ts...>, Component> {
    using type = std::tuple<Component<Ts>...>;
}

using MyTuple = std::tuple<int, double, char>;
using MyTransformedTuple = typename transform_tuple<MyTuple, std::shared_ptr>::type;

Более общее решение лучше всего работает с c++17 или более поздней версией. До этого он соответствовал бы только шаблону с ровно 1 параметром. После c++17 он также сможет сопоставляться с чем-то вроде std::vector, у которого есть 2 параметра шаблона, где второй имеет аргумент по умолчанию.

Редактировать:
Как указано в комментариях @ Jarod42 и @Caleth мы можем улучшить это немного больше.

template <typename Tuple, template <typename...> typename Component>
struct transform_tuple;

Пакет параметров для параметра шаблона шаблона позволяет нам передавать что-то вроде std::vector из c++11 и вперед. Это оставляет проблемы, только если мы хотим передать что-то, смешивающее типовые и нетиповые параметры, такие как std::array.

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

template <typename T>
using FixedArray10 = std::array<T, 10>;

using MyTransformedTuple = typename transform_tuple<MyTuple, FixedArray10>::type;
...