将元组类型转换为另一种元组类型

Dav*_*vid 1 c++ variadic-templates

假设我有一个元组类型std::tuple<x,y,z>,或者可能是std::tuple<a,b>. 我想要一种通用的方法来转换我的元组中的类型,例如“函数化”以获得

std::tuple<std::function<void(x)>,
           std::function<void(y)>,
           std::function<void(z)>>
Run Code Online (Sandbox Code Playgroud)

或者可能为 shared_pointers 获取存储空间,例如

std::tuple<std::shared_pointer<a>,
           std::shared_pointer<b>>
Run Code Online (Sandbox Code Playgroud)

我将如何使用 C++17 实现这一目标?C++20 回答有趣但不适用于我目前的情况。

动机:我有一个类,它将被一个任意类型的列表参数化,不一定是唯一的类型,并且希望列表中的每个类型都有一个 std::function 成员。

sup*_*per 5

模板专业化可能是最简单的方法。

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;
Run Code Online (Sandbox Code Playgroud)

为了使其更通用,您可以接受模板模板参数以应用于包。

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;
Run Code Online (Sandbox Code Playgroud)

更通用的解决方案在使用c++17或稍后使用时效果最佳。在此之前,它只会匹配只有 1 个参数的模板。之后c++17它也可以匹配std::vector具有 2 个模板参数的东西,其中第二个具有默认参数。

编辑:
正如@Jarod42 和@Caleth 在评论中指出的那样,我们可以对此进行更多改进。

template <typename Tuple, template <typename...> typename Component>
struct transform_tuple;
Run Code Online (Sandbox Code Playgroud)

模板模板参数的参数包允许我们传递诸如std::vectorin fromc++11和 forward 之类的东西。如果我们想传递混合类型和非类型参数的东西,比如std::array.

我们可以通过使用模板别名来部分解决这个问题。

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

using MyTransformedTuple = typename transform_tuple<MyTuple, FixedArray10>::type;
Run Code Online (Sandbox Code Playgroud)