You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在变参模板中按需展开容器类型实现Variant包装器?

问题:实现支持自动展开容器类型的std::variant包装器

我想要创建一个std::variant的包装器,能将传入的各类类型(包括容器内的类型)用Wrapper包装后放入variant中。核心需求是:根据类型是否为容器(比如tuple),自动展开内部类型并放入variant。

现有代码

template <typename T>
struct Wrapper
{};

template <typename>
struct has_expandable_types : std::false_type
{};

template <template <typename...> class T, typename... Args>
struct has_expandable_types<T<Args...>> : std::true_type
{};

template <template <typename> class T, typename... Types>
struct Variant_wrapper;
template <template <typename> class T, typename U, typename... Types>
struct Variant_wrapper_expanded;

template <template <typename> class T, typename... Types>
struct Variant_wrapper : std::variant<T<Types>...>
{};

template <template <typename> class T, template <typename...> class U, typename... UTypes>
struct Variant_wrapper_expanded <T, U<UTypes...>> : Variant_wrapper<T, UTypes...>
{};

using Types = std::tuple<int, float>;

int main()
{
    //std::variant< Wrapper<int>, Wrapper<float> >, OK
    Variant_wrapper<Wrapper, int, float> var; 

    //std::variant< Wrapper<int>, Wrapper<float> >, OK
    Variant_wrapper_expanded<Wrapper, Types> var2;

    //std::variant< Wrapper<int>, Wrapper<float> >, NOT OK
    // EXPECTED std::variant< Wrapper<int>, Wrapper<float>, Wrapper<double> >
    //can't capture a second parameter pack?
    Variant_wrapper_expanded<Wrapper, Types, double> var3;
}

理想用法示例

//produces std::variant< Wrapper<std::string>, Wrapper<int>, Wrapper<float>, Wrapper<double> >
Variant_wrapper<Wrapper, std::string, Types, double> var; 

具体问题

  • 问题1:在var3示例中,无法捕获tuple之后的剩余类型(比如double),该如何处理这类剩余参数包?
  • 问题2:向Variant_wrapper传入tuple类型时,会直接包装整个tuple而非展开内部类型,怎么实现自动展开?

解决方案

核心思路是先实现一个类型展开元函数,递归处理每个传入类型:遇到可展开容器(如tuple)则展开内部元素,否则保留原类型;最后将所有处理后的类型收集起来生成目标std::variant。

完整实现代码

#include <variant>
#include <tuple>
#include <type_traits>
#include <vector>

template <typename T>
struct Wrapper {};

// 标记类型是否可展开(可扩展支持其他容器)
template <typename>
struct is_expandable : std::false_type {};

// 支持tuple展开
template <typename... Args>
struct is_expandable<std::tuple<Args...>> : std::true_type {};

// 支持vector展开(可选,按需添加其他容器)
template <typename T>
struct is_expandable<std::vector<T>> : std::true_type {};

// 递归展开所有传入类型的元函数
template <typename... Types>
struct expand_types;

// 终止条件:空参数包
template <>
struct expand_types<> {
    using type = std::tuple<>;
};

// 处理可展开的tuple类型
template <typename... Args, typename... Rest>
struct expand_types<std::tuple<Args...>, Rest...> {
    using type = decltype(
        std::tuple_cat(
            std::declval<std::tuple<Args...>>(),
            std::declval<typename expand_types<Rest...>::type>()
        )
    );
};

// 处理可展开的vector类型(单元素容器)
template <typename T, typename... Rest>
struct expand_types<std::vector<T>, Rest...> {
    using type = decltype(
        std::tuple_cat(
            std::declval<std::tuple<T>>(),
            std::declval<typename expand_types<Rest...>::type>()
        )
    );
};

// 处理不可展开的普通类型
template <typename NonExpandable, typename... Rest>
requires (!is_expandable<NonExpandable>::value)
struct expand_types<NonExpandable, Rest...> {
    using type = decltype(
        std::tuple_cat(
            std::declval<std::tuple<NonExpandable>>(),
            std::declval<typename expand_types<Rest...>::type>()
        )
    );
};

// 辅助别名:简化展开类型的调用
template <typename... Types>
using expand_types_t = typename expand_types<Types...>::type;

// 从展开后的tuple生成最终的variant包装器
template <template <typename> class Wrapper, typename... Types>
struct Variant_wrapper_impl;

template <template <typename> class Wrapper, typename... ExpandedTypes>
struct Variant_wrapper_impl<Wrapper, std::tuple<ExpandedTypes...>> {
    using type = std::variant<Wrapper<ExpandedTypes>...>;
};

// 对外暴露的最终包装器:自动处理所有类型展开
template <template <typename> class Wrapper, typename... Types>
using Variant_wrapper = typename Variant_wrapper_impl<Wrapper, expand_types_t<Types...>>::type;

测试验证

using Types = std::tuple<int, float>;

int main() {
    // 生成 std::variant<Wrapper<int>, Wrapper<float>>
    Variant_wrapper<Wrapper, int, float> var;

    // 生成 std::variant<Wrapper<int>, Wrapper<float>>
    Variant_wrapper<Wrapper, Types> var2;

    // 生成 std::variant<Wrapper<int>, Wrapper<float>, Wrapper<double>>
    Variant_wrapper<Wrapper, Types, double> var3;

    // 理想用法:生成 std::variant<Wrapper<std::string>, Wrapper<int>, Wrapper<float>, Wrapper<double>>
    Variant_wrapper<Wrapper, std::string, Types, double> var4;

    // 支持vector展开:生成 std::variant<Wrapper<int>, Wrapper<float>>
    Variant_wrapper<Wrapper, std::vector<int>, std::vector<float>> var5;
}

关键说明

  1. 参数包捕获:通过expand_types的递归逻辑,自动处理所有传入的参数包,包括容器之后的普通类型(如double)。
  2. 自动展开逻辑:is_expandable标记可展开类型,expand_types递归遍历并展开所有容器内部元素,最终合并为一个完整的类型tuple。
  3. 扩展性:如需支持其他容器(如std::array),只需添加对应的is_expandable特化和expand_types处理分支即可。

内容的提问来源于stack exchange,提问作者kbz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:53:10