不能。折叠表达式仅作用于参数包,不支持对普通数组、std::array或std::vector直接展开;需借助std::index_sequence将索引转为参数包,再通过arr[Is]等形式间接展开元素。

折叠表达式能直接展开数组吗
不能。C++ 的折叠表达式(...)只作用于参数包(parameter pack),不支持对普通数组、std::array 或 std::vector 直接展开。你写 arr(...) 或 (arr + ...) 会编译失败——编译器根本找不到参数包。
怎么用折叠表达式“间接”处理数组元素
核心思路是把数组转成参数包。常见做法是配合 std::index_sequence 和模板参数推导,把数组索引变成包,再用折叠表达式访问对应元素。
例如,对 int arr[4] = {1,2,3,4}; 求和:
template<size_t... Is>
constexpr int sum_impl(const int* arr, std::index_sequence<Is...>) {
return (arr[Is] + ...); // ✅ 合法折叠:arr[Is] 构成参数包
}
<p>template<size_t N>
constexpr int array_sum(const int (&arr)[N]) {
return sum_impl(arr, std::make_index_sequence<N>{});
}-
std::make_index_sequence<N>生成0,1,...,N-1的非类型模板参数包 -
arr[Is]在展开时变成arr[0], arr[1], ..., arr[N-1],满足折叠要求 - 注意:必须用引用形参
const int (&arr)[N]捕获数组大小,否则N无法推导
用 std::array 更简洁的写法
std::array 支持 data() 和 size(),且类型包含长度信息,比原生数组更容易配合折叠表达式:
立即学习“C++免费学习笔记(深入)”;
template<typename T, size_t N>
constexpr T array_sum(const std::array<T, N>& a) {
return [&](const auto& arr) constexpr {
return (arr.data()[0] + ... + arr.data()[N-1]); // ❌ 错!N 不是模板参数包
}(a);
}上面写法不行——N 是值,不是包。正确方式仍是走 index_sequence:
template<typename T, size_t N, size_t... Is>
constexpr T sum_array_impl(const std::array<T, N>& a, std::index_sequence<Is...>) {
return (a[Is] + ...);
}
<p>template<typename T, size_t N>
constexpr T array_sum(const std::array<T, N>& a) {
return sum_array_impl(a, std::make_index_sequence<N>{});
}- 所有操作必须在 constexpr 上下文中完成,否则无法在编译期求值
- 如果只是运行时处理,直接用 range-based for 更清晰,没必要硬套折叠表达式
- 折叠方向影响语义:
(... + a[Is])是左折叠,(a[Is] + ...)是右折叠;对+无区别,但对-或/有差异
为什么不用 std::apply 简化
C++17 的 std::apply 可以把元组(或 std::array)解包为函数参数,天然适配折叠表达式:
template<typename T, size_t N>
constexpr T array_sum(const std::array<T, N>& a) {
return std::apply([](auto&&... xs) constexpr { return (xs + ...); }, a);
}这行代码能工作,因为:
-
std::array可隐式转换为元组等价物(满足std::tuple_size等要求) -
std::apply把每个元素作为独立实参传入 lambda,形成参数包xs... -
(xs + ...)对这个包进行折叠 - 但注意:
std::apply要求std::array是字面量类型且元素可 constexpr 构造;对非 trivial 类型可能受限
原生数组仍不支持 std::apply,必须先转成 std::array 或用 index_sequence 手动解包。
真正容易被忽略的是:折叠表达式本身不操作内存布局,它只是一种语法糖,背后依赖模板实例化和参数包展开机制。想绕过参数包直接“折叠数组”,目前没有标准途径。


















