You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:35:31