构造模板化元组类型:简化函数模板的元组别名需求
如何用模板化元组别名简化条件元组返回的函数?
首先明确你的需求:你希望用模板别名替代重复书写多次相同类型的std::tuple定义,让原始函数的返回类型声明更简洁。答案是完全可以,我们可以借助C++模板元编程工具来实现这个需求。
先看你原来的函数模板:
template< bool b, RT = std::conditional_t<b, std::tuple<int, int, int, int>, std::tuple<int, int, int, int, double, double, double, double> > RT function() { int i1, i2, i3, i4; if constexpr(b) { double i5, i6, i7, i8; return { i1, i2, i3, i4, i5, i6, i7, i8 }; } else { return { i1, i2, i3, i4 }; } }
你想要的tuple_t模板别名,本质是生成包含N次重复类型的元组,我们分阶段来实现:
1. 实现单类型重复N次的元组别名
先搞定最基础的版本:给定类型T和次数N,生成包含N个T的元组。我们可以用std::index_sequence辅助生成类型序列:
#include <tuple> #include <utility> // 内部辅助模板,负责生成重复类型的元组 template<typename T, std::size_t N, typename = std::make_index_sequence<N>> struct RepeatTupleImpl; // 特化版本:利用索引序列的长度来重复T类型 template<typename T, std::size_t N, std::size_t... Indices> struct RepeatTupleImpl<T, N, std::index_sequence<Indices...>> { // Indices只是占位符,用来凑够N个T的位置 using Type = std::tuple<decltype((void)Indices, std::declval<T>())...>; }; // 对外暴露的简洁别名 template<typename T, std::size_t N> using RepeatTuple = typename RepeatTupleImpl<T, N>::Type;
现在你可以用RepeatTuple<int, 4>代替std::tuple<int, int, int, int>,用RepeatTuple<double, 4>代替四个double的元组,代码瞬间清爽很多!
2. 实现多类型多重复次数的组合元组
如果要支持“先N1次T1,再N2次T2”的组合,我们可以把上面的单类型元组拼接起来。先写一个元组类型拼接的辅助工具:
// 辅助模板:拼接两个元组类型 template<typename TupleA, typename TupleB> struct ConcatTupleImpl; // 特化版本:展开两个元组的类型并拼接 template<typename... Ts, typename... Us> struct ConcatTupleImpl<std::tuple<Ts...>, std::tuple<Us...>> { using Type = std::tuple<Ts..., Us...>; }; template<typename TupleA, typename TupleB> using ConcatTuple = typename ConcatTupleImpl<TupleA, TupleB>::Type; // 双类型重复的别名 template<typename T1, std::size_t N1, typename T2, std::size_t N2> using DualRepeatTuple = ConcatTuple<RepeatTuple<T1, N1>, RepeatTuple<T2, N2>>;
这里要注意:C++不允许同名模板别名有不同的模板参数列表(你写的两个tuple_t会编译报错),所以我们给不同功能的别名起不同名字,避免冲突。
3. 用新别名简化你的原始函数
现在把这些工具用在你的函数里,代码会变得非常简洁:
#include <tuple> #include <utility> // 上面的RepeatTupleImpl、RepeatTuple、ConcatTupleImpl、ConcatTuple、DualRepeatTuple定义放在这里 template<bool b> auto function() { // 用std::conditional_t选择对应的返回类型 using ReturnType = std::conditional_t<b, RepeatTuple<int, 4>, DualRepeatTuple<int, 4, double, 4>>; int i1 = 0, i2 = 0, i3 = 0, i4 = 0; // 记得初始化变量哦 if constexpr(b) { double i5 = 0.0, i6 = 0.0, i7 = 0.0, i8 = 0.0; return ReturnType{i1, i2, i3, i4, i5, i6, i7, i8}; } else { return ReturnType{i1, i2, i3, i4}; } }
可选:更通用的多类型重复元组
如果你以后需要支持更多类型的重复(比如int,2, double,3, float,1),可以写一个递归的可变参数版本:
// 递归拼接的辅助模板 template<typename... Args> struct MultiRepeatTupleImpl; // 终止条件:没有参数时返回空元组 template<> struct MultiRepeatTupleImpl<> { using Type = std::tuple<>; }; // 递归步骤:处理第一个(类型,次数)对,再拼接剩余的 template<typename T, std::size_t N, typename... Rest> struct MultiRepeatTupleImpl<T, std::integral_constant<std::size_t, N>, Rest...> { using Type = ConcatTuple<RepeatTuple<T, N>, typename MultiRepeatTupleImpl<Rest...>::Type>; }; // 对外的通用别名,用法:MultiRepeatTuple<int,4, double,4> template<typename T, std::size_t N, typename... Rest> using MultiRepeatTuple = typename MultiRepeatTupleImpl<T, std::integral_constant<std::size_t, N>, Rest...>::Type;
这个版本可以支持任意数量的“类型+次数”组合,扩展性拉满!
内容的提问来源于stack exchange,提问作者Bilentor
相关产品推荐
相关产品推荐

