如何在变参模板中按需展开容器类型实现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; }
关键说明
- 参数包捕获:通过
expand_types的递归逻辑,自动处理所有传入的参数包,包括容器之后的普通类型(如double)。 - 自动展开逻辑:
is_expandable标记可展开类型,expand_types递归遍历并展开所有容器内部元素,最终合并为一个完整的类型tuple。 - 扩展性:如需支持其他容器(如
std::array),只需添加对应的is_expandable特化和expand_types处理分支即可。
内容的提问来源于stack exchange,提问作者kbz
相关产品推荐
相关产品推荐

