std::for_each
在头文件 <algorithm> 中定义 |
||
template< class InputIt, class UnaryFunc > UnaryFunc for_each( InputIt first, InputIt last, UnaryFunc f ); |
(1) | (constexpr 自 C++20 起) |
template< class ExecutionPolicy, class ForwardIt, class UnaryFunc > void for_each( ExecutionPolicy&& policy, |
(2) | (自 C++17 起) |
将给定的函数对象 f 应用于范围 [
first,
last)
中每个迭代器解引用的结果。如果 f 返回结果,则忽略该结果。
std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> 为 true 时,此重载才参与重载决议。 |
(直至 C++20) |
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> 为 true。 |
(自 C++20 起) |
UnaryFunc
不 可复制构造,则行为未定义。若迭代器类型 (InputIt
/ForwardIt
) 是可变的,则 f 可以通过解引用的迭代器修改范围中的元素。
与其余并行算法不同,即使序列中的元素 可平凡复制,for_each
也不允许创建它们的副本。
目录 |
[编辑] 参数
first, last | - | 要对其应用函数的范围 |
policy | - | 要使用的执行策略。 细节参见 执行策略。 |
f | - | 函数对象,要应用于范围 [ first, last) 中每个迭代器解引用的结果函数的签名应等价于以下内容 void fun(const Type &a); 签名不需要有 const &。 |
类型要求 | ||
-InputIt 必须满足 旧式输入迭代器 的要求。 | ||
-ForwardIt 必须满足 旧式前向迭代器 的要求。 |
[编辑] 返回值
[编辑] 复杂度
恰好应用 std::distance(first, last) 次 f。
[编辑] 异常
带有名为 ExecutionPolicy
的模板参数的重载按如下方式报告错误
- 若作为算法的一部分调用的函数的执行抛出异常且
ExecutionPolicy
是 标准策略 之一,则调用 std::terminate。 对于任何其他ExecutionPolicy
,行为是实现定义的。 - 若算法未能分配内存,则抛出 std::bad_alloc。
[编辑] 可能的实现
另见 libstdc++、libc++ 和 MSVC stdlib 中的实现。
template<class InputIt, class UnaryFunc> constexpr UnaryFunc for_each(InputIt first, InputIt last, UnaryFunc f) { for (; first != last; ++first) f(*first); return f; // implicit move since C++11 } |
[编辑] 注意
对于重载 (1),f 可以是有状态函数对象。 返回值可以视为批处理操作的最终状态。
对于重载 (2),可以创建 f 的多个副本以执行并行调用。 不返回值是因为并行化通常不允许高效的状态累积。
[编辑] 示例
以下示例使用 lambda 表达式 增加向量的所有元素,然后在函数对象(又称“函子”)中使用重载的 operator()
计算它们的总和。 请注意,要计算总和,建议使用专用算法 std::accumulate。
#include <algorithm> #include <iostream> #include <vector> int main() { std::vector<int> v{3, -4, 2, -8, 15, 267}; auto print = [](const int& n) { std::cout << n << ' '; }; std::cout << "before:\t"; std::for_each(v.cbegin(), v.cend(), print); std::cout << '\n'; // increment elements in-place std::for_each(v.begin(), v.end(), [](int &n) { n++; }); std::cout << "after:\t"; std::for_each(v.cbegin(), v.cend(), print); std::cout << '\n'; struct Sum { void operator()(int n) { sum += n; } int sum {0}; }; // invoke Sum::operator() for each element Sum s = std::for_each(v.cbegin(), v.cend(), Sum()); std::cout << "sum:\t" << s.sum << '\n'; }
输出
before: 3 -4 2 -8 15 267 after: 4 -3 3 -7 16 268 sum: 281
[编辑] 缺陷报告
以下更改行为的缺陷报告已追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 发布时的行为 | 正确行为 |
---|---|---|---|
LWG 475 | C++98 | 不清楚 f 是否可以修改 正在迭代的序列的元素( for_each 被归类为“非修改序列操作”) |
已澄清(若迭代器类型是可变的则允许) |
LWG 2747 | C++11 | 重载 (1) 返回 std::move(f) | 返回 f(其隐式移动) |
[编辑] 参见
将函数应用于元素范围,并将结果存储在目标范围中 (函数模板) | |
(C++17) |
将函数对象应用于序列的前 N 个元素 (函数模板) |
(C++20) |
将函数应用于元素范围 (niebloid) |
(C++20) |
将函数对象应用于序列的前 N 个元素 (niebloid) |
范围-for 循环(C++11) |
在范围内执行循环 |