如何通过C++模板特化或辅助结构体展开tag类型参数?
解决方案
最简实现(针对单个tag参数)
如果只需要处理第二个参数是tag<...>的场景,通过模板特化的辅助结构体就能实现:
// 原tag结构体 template<typename...> struct tag{}; // 原Impl类模板 template <typename T, typename ...Args> class Impl { public: T func(Args...); }; // 辅助解析结构体:基础情况(无tag参数) template<typename T, typename... Args> struct ImplResolver { using type = Impl<T, Args...>; }; // 辅助解析结构体:特化处理tag参数 template<typename T, typename... TagArgs> struct ImplResolver<T, tag<TagArgs...>> { using type = Impl<T, TagArgs...>; }; // 别名模板,简化使用 template<typename T, typename... Args> using ImplAlias = typename ImplResolver<T, Args...>::type;
使用方式:
// 等价于 Impl<int, int, double> using MyImpl = ImplAlias<int, tag<int, double>>;
通用实现(支持任意数量/嵌套的tag)
如果需要支持多个tag参数,甚至嵌套的tag(比如tag<tag<int>, double>),可以通过递归展开所有tag类型实现:
#include <tuple> template<typename...> struct tag{}; template <typename T, typename ...Args> class Impl { public: T func(Args...); }; // 辅助:展开单个类型,若为tag则递归展开内部参数,否则返回自身 template<typename T> struct UnpackTag { using type = std::tuple<T>; }; template<typename... Args> struct UnpackTag<tag<Args...>> { using type = typename UnpackTag<Args...>::type; }; // 辅助:展开所有参数中的tag,合并为一个tuple template<typename... Args> struct UnpackAllTags; template<typename... Args> using UnpackAllTags_t = typename UnpackAllTags<Args...>::type; // 空参数包的情况 template<> struct UnpackAllTags<> { using type = std::tuple<>; }; // 处理非tag类型 + 剩余参数 template<typename T, typename... Rest> struct UnpackAllTags<T, Rest...> { using type = decltype(std::tuple_cat( UnpackTag<T>::type{}, UnpackAllTags_t<Rest...>{} )); }; // 处理tag类型 + 剩余参数 template<typename... TagArgs, typename... Rest> struct UnpackAllTags<tag<TagArgs...>, Rest...> { using type = decltype(std::tuple_cat( UnpackAllTags_t<TagArgs...>{}, UnpackAllTags_t<Rest...>{} )); }; // 辅助:从tuple生成对应的Impl类型 template<typename T, typename Tuple> struct ImplFromTuple; template<typename T, typename... Args> struct ImplFromTuple<T, std::tuple<Args...>> { using type = Impl<T, Args...>; }; // 最终的别名模板 template<typename T, typename... Args> using ImplAlias = typename ImplFromTuple<T, UnpackAllTags_t<Args...>>::type;
使用示例:
// 等价于 Impl<int, int, double> using MyImpl1 = ImplAlias<int, tag<int, double>>; // 等价于 Impl<int, int, double, float> using MyImpl2 = ImplAlias<int, tag<int, double>, tag<float>>; // 等价于 Impl<int, int, double>(嵌套tag展开) using MyImpl3 = ImplAlias<int, tag<tag<int>, double>>;
为什么你之前的尝试不行?
你尝试在tag里定义using types = Args;不被允许,是因为C++不允许直接把可变参数包作为类型别名的定义,必须将其包裹在模板或容器(比如std::tuple)中,才能通过类型别名传递。
内容的提问来源于stack exchange,提问作者billbillybill
相关产品推荐
相关产品推荐

