C++编译期计算std::integral_constant元组前缀和的方法
编译期计算std::integral_constant元组的前缀和
需求为对存储在std::tuple中的std::integral_constant序列做编译期前缀和计算,优先采用返回类型自动推导的函数实现,降低模板元编程编写复杂度。
输入输出示例
输入类型示例:
using in_t = std::tuple< std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,2> >;
期望返回类型:
std::tuple< std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,2>, std::integral_constant<unsigned __int64,4> >;
给定函数框架:
template <typename Tuple> constexpr decltype(auto) prefixSum(Tuple t) { // ? } int main () { using in_t = std::tuple< std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,2> >; using out_t = decltype(prefixSum<in_t>()); }
原有实现的问题
你之前写的递归实现存在两个核心问题:
- 硬编码值类型为
std::size_t,和输入的unsigned __int64类型不匹配 - 手动递归传递偏移量的写法冗余,且容易触发模板递归深度限制,实际上用索引序列+折叠表达式的写法可以完全规避这些问题。
可直接运行的实现(C++20)
以下实现完全匹配给定框架,自动推导返回类型,无需手动写模板特化,支持任意数值类型的std::integral_constant元组:
#include <tuple> #include <cstdint> #include <utility> #include <type_traits> template <typename Tuple, std::size_t... Is> constexpr auto prefixSumImpl(Tuple&& t, std::index_sequence<Is...>) { constexpr auto calcUpToIdx = []<std::size_t I>(std::integral_constant<std::size_t, I>, auto&& tuple) { using ValueType = typename std::tuple_element_t<0, std::remove_cvref_t<decltype(tuple)>>::value_type; return [&tuple]<std::size_t... Js>(std::index_sequence<Js...>) { return std::integral_constant<ValueType, (std::get<Js>(tuple).value + ... + ValueType{0})>{}; }(std::make_index_sequence<I + 1>{}); }; return std::make_tuple(calcUpToIdx(std::integral_constant<std::size_t, Is>{}, std::forward<Tuple>(t))...); } template <typename Tuple> constexpr decltype(auto) prefixSum(Tuple&& t = {}) { return prefixSumImpl(std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<Tuple>>>{}); } // 验证用例 int main () { using in_t = std::tuple< std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,2> >; using out_t = decltype(prefixSum<in_t>()); // 编译期校验结果类型完全符合预期 static_assert(std::is_same_v<out_t, std::tuple< std::integral_constant<unsigned __int64,1>, std::integral_constant<unsigned __int64,2>, std::integral_constant<unsigned __int64,4> >>); }
实现说明
- 基于
std::index_sequence做元组索引展开,没有手动递归逻辑,编译器对索引序列的展开深度支持远高于手动模板递归的默认阈值,常规长度的元组不会触发深度限制 - 自动从元组第一个元素提取值类型,不会出现硬编码类型和输入不匹配的问题
- 所有计算完全在编译期完成,返回的每个元素都是对应前缀和值的
std::integral_constant实例,类型完全匹配预期 - 给入参加了默认值,支持
prefixSum<in_t>()的空参调用写法,完全符合给定的函数框架要求
内容的提问来源于stack exchange,提问作者Chris G.
相关产品推荐
相关产品推荐

