std::for_each
定义于头文件 <algorithm> |
||
template< class InputIt, class UnaryFunc > UnaryFunc for_each( InputIt first, InputIt last, UnaryFunc f ); |
(1) | (C++20 起为 constexpr) |
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 起) |
如果迭代器类型 (InputIt
/ForwardIt
) 是可变的,f 可以通过解引用迭代器修改范围的元素。
与其他并行算法不同,for_each
不允许复制序列中的元素,即使它们是可平凡复制的 (TriviallyCopyable)。
目录 |
[编辑] 参数
first, last | - | 迭代器对,定义了要应用函数对象的元素范围 [ first, last) |
policy | - | 要使用的 执行策略 |
f | - | 函数对象,将应用于范围 [ first, last) 中每个迭代器解引用后的结果函数的签名应等效于以下内容 void fun(const Type &a); 签名不需要有 const &。 |
类型要求 | ||
-InputIt 必须满足 LegacyInputIterator 的要求。 | ||
-ForwardIt 必须满足 LegacyForwardIterator 的要求。 |
[编辑] 返回值
[编辑] 复杂度
精确地 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++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
LWG 475 | C++98 | 不清楚 f 是否可以修改 正在迭代的序列元素( for_each 被归类为“非修改序列操作”) |
明确(如果 迭代器类型是可变的,则允许) |
LWG 2747 | C++11 | 重载 (1) 返回 std::move(f) | 返回 f(其隐式移动) |
[编辑] 另请参阅
对一个范围的元素应用函数,并将结果存储在目标范围中 (函数模板) | |
(C++17) |
对序列中的前 N 个元素应用函数对象 (函数模板) |
(C++20) |
对范围中的元素应用一元函数对象 (算法函数对象) |
(C++20) |
对序列中的前 N 个元素应用函数对象 (算法函数对象) |
range-for 循环(C++11) |
执行范围上的循环 |