std::for_each
来自 zh.cppreference.net
| 定义于头文件 <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,
ForwardIt first, ForwardIt last, UnaryFunc f );
|
(2) | (自 C++17 起) |
应用给定的可调用对象 f 到目标范围 [first, last) 中的每个元素。如果 f 返回结果,则忽略该结果。
2)
f 可能不是按顺序应用。算法根据 policy 执行。 与其他 并行算法不同,
for_each 不允许对目标范围中的元素进行任意复制。 仅当以下表达式的值为
true 时,此重载才参与重载决议:
|
|
(直到 C++20) |
|
|
(自 C++20 起) |
如果
UnaryFunc 不是 CopyConstructible,则行为未定义。参数
| first, last | - | 定义目标的迭代器对range |
| f | - | 应用于元素的函数对象 函数的签名应等价于以下形式:
签名不需要包含 |
| policy | - | 使用的执行策略 |
| 类型要求 | ||
-InputIt 必须满足 LegacyInputIterator 的要求。
| ||
-ForwardIt 必须满足 LegacyForwardIterator 的要求。
| ||
返回值
1)
f复杂度
正好 std::distance(first, last) 次应用 f。
异常
2) 在执行过程中:
- 如果并行化所需的临时内存资源不可用,则抛出 std::bad_alloc。
- 如果通过算法参数访问对象时抛出未捕获的异常,则行为由执行策略确定(对于 标准策略,会调用 std::terminate)。
注解
如果迭代器类型 (InputIt/ForwardIt) 是可变的,则 f 可以修改目标范围内的元素。
对于重载 (1),f 可以是有状态的可调用对象。返回值可视为批量操作的最终状态。
对于重载 (2),可能会创建 f 的多个副本以执行并行调用。由于并行化通常不允许高效的状态累积,因此不返回值。
可能的实现
另见 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
}
|
示例
以下示例使用 lambda 表达式来递增 vector 的所有元素,然后使用可调用对象中的重载 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++20) |
将一元函数对象应用于范围 中的元素(算法函数对象) |
(C++17) |
将函数对象应用于序列的前 N 个元素 (函数模板 & 算法函数对象) |
(C++20) |
|
| 将一个函数应用于元素范围,并将结果存储在目标范围中 (函数模板 & 算法函数对象) | |
(C++20) |
|
基于范围的forfor 循环(C++11)
|
在范围内执行循环 |