C++17/20编译时同长度数组逐元素相加的模板编程问题
编译时同长度整数序列逐元素相加的C++模板实现
你当前的addSeq模板参数声明存在错误——template<template<int...> typename...Seqs>接收的是模板类型(比如Seq本身),但你实际要传入的是模板实例(比如Seq<1,2,3>),所以需要修正模板参数为template<typename... Seqs>,再通过模板特化或辅助逻辑完成逐元素求和。以下是两种可行的实现方式:
方式一:递归模板特化(兼容C++17)
通过递归逐步合并序列,同时在编译期校验序列长度一致性:
#include <type_traits> // 定义表示整数序列的结构体 template <int... I> struct Seq {}; // 辅助模板:递归合并多个序列 template <typename... Seqs> struct add_seqs_impl; // 递归终止条件:单个序列直接返回自身 template <int... Is> struct add_seqs_impl<Seq<Is...>> { using type = Seq<Is...>; }; // 递归步骤:合并前两个序列,再与剩余序列继续合并 template <int... First, int... Rest, typename... Others> struct add_seqs_impl<Seq<First...>, Seq<Rest...>, Others...> { // 编译期强制所有序列长度相同,否则报错 static_assert(sizeof...(First) == sizeof...(Rest), "所有序列必须长度相同"); // 逐元素相加前两个序列,再递归处理剩余序列 using type = typename add_seqs_impl<Seq<First + Rest...>, Others...>::type; }; // 对外暴露的addSeq模板 template <typename... Seqs> struct addSeq { using type = typename add_seqs_impl<Seqs...>::type; }; // 测试验证 int main() { static_assert(std::is_same_v<addSeq<Seq<1,2,3>, Seq<2,4,6>, Seq<3,6,9>>::type, Seq<6,12,18>>); static_assert(std::is_same_v<addSeq<Seq<5>>::type, Seq<5>>); static_assert(std::is_same_v<addSeq<Seq<1,1>, Seq<2,2>>::type, Seq<3,3>>); // 下面这行会编译报错(序列长度不一致) // static_assert(std::is_same_v<addSeq<Seq<1,2>, Seq<3>>::type, Seq<4,2>>); }
关键说明
add_seqs_impl通过递归逐步合并序列:每次将前两个序列的对应元素相加生成新序列,再与剩余序列重复该操作。static_assert确保所有参与相加的序列长度一致,错误会在编译阶段直接暴露。
方式二:C++17折叠表达式(更简洁)
借助std::index_sequence生成索引,用折叠表达式一次性完成所有序列的逐元素求和:
#include <type_traits> #include <tuple> #include <utility> // 定义表示整数序列的结构体 template <int... I> struct Seq {}; // 辅助模板:编译期获取序列长度 template <typename T> struct seq_size; template <int... Is> struct seq_size<Seq<Is...>> : std::integral_constant<std::size_t, sizeof...(Is)> {}; template <typename T> constexpr std::size_t seq_size_v = seq_size<T>::value; // 辅助函数:提取序列指定索引的元素 template <std::size_t Idx, int... Is> constexpr int get_seq_element(Seq<Is...>) { return std::get<Idx>(std::integer_sequence<int, Is...>{}); } // 对外暴露的addSeq模板 template <typename... Seqs> struct addSeq { // 获取第一个序列的长度作为基准 static constexpr std::size_t seq_length = seq_size_v<std::tuple_element_t<0, std::tuple<Seqs...>>>; // 编译期校验所有序列长度一致 static_assert(((seq_size_v<Seqs> == seq_length) && ...), "所有序列必须长度相同"); // 生成结果序列的辅助逻辑 template <std::size_t... Idxs> static constexpr auto make_result(std::index_sequence<Idxs...>) { // 折叠表达式:对每个索引位置的所有元素求和 return Seq<(get_seq_element<Idxs>(Seqs{}) + ...)>{}; } // 推导最终结果类型 using type = decltype(make_result(std::make_index_sequence<seq_length>())); }; // 测试验证 int main() { static_assert(std::is_same_v<addSeq<Seq<1,2,3>, Seq<2,4,6>, Seq<3,6,9>>::type, Seq<6,12,18>>); static_assert(std::is_same_v<addSeq<Seq<10,20>, Seq<30,40>, Seq<50,60>>::type, Seq<90,120>>); }
关键说明
seq_size和get_seq_element分别用于编译期获取序列长度、提取指定位置元素。- 借助
std::make_index_sequence生成索引序列,通过折叠表达式(get_seq_element<Idxs>(Seqs{}) + ...)一次性完成所有序列对应位置的元素求和,代码更紧凑。
内容的提问来源于stack exchange,提问作者blackYellow
相关产品推荐
相关产品推荐

