Namespaces
Variants

std::for_each

来自 zh.cppreference.net
 
 
算法库
受约束算法和范围上的算法 (C++20)
受约束算法,例如 ranges::copy, ranges::sort, ...
排序和相关操作
划分操作
(C++11)    

排序操作
二分查找操作
(在已划分的范围上)
集合操作 (在有序范围上)
合并操作 (在有序范围上)
堆操作
最小/最大操作
(C++11)
(C++17)
字典序比较操作
排列操作


 
定义于头文件 <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 返回结果,则忽略该结果。

1) f 从 first 开始按顺序应用。

如果 UnaryFunc 不是 MoveConstructible,则行为未定义。

(自 C++11 起)
2) f 可能不是按顺序应用。算法根据 policy 执行。
与其他 并行算法不同,for_each 不允许对目标范围中的元素进行任意复制。
仅当以下表达式的值为 true 时,此重载才参与重载决议:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(直到 C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(自 C++20 起)
如果 UnaryFunc 不是 CopyConstructible,则行为未定义。

参数

first, last - 定义目标的迭代器对range
f - 应用于元素的函数对象

函数的签名应等价于以下形式:

void fun(const Type &a);

签名不需要包含 const &。
类型 Type 必须使得类型 InputIt 的对象可以被解引用并隐式转换为 Type。

​

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(会隐式移动)

参阅

将一元函数对象应用于范围
中的元素(算法函数对象)
将函数对象应用于序列的前 N 个元素
(函数模板 & 算法函数对象)
将一个函数应用于元素范围,并将结果存储在目标范围中
(函数模板 & 算法函数对象)
基于范围的forfor 循环(C++11) 在范围内执行循环