【C++】泛型算法之std::for_each

std::for_each是一个C++标准库中的算法,用于遍历容器的元素,执行指定操作。它提供了函数式编程的风格,有利于编译器优化,且在C++17以后支持并行执行。文章通过示例展示了如何使用std::for_each进行元素遍历、求和以及并行计算,并指出其对比传统for循环的语义优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

std::for_each用于逐个遍历容器元素,它对迭代器区间[first, last)所指的每一个元素,执行由单参数函数对象f所定义的操作。它是for循环的一种替代方案。

尽管,我们仍可以使用for循环进行一个容器元素的遍历,但是std::for_each额外给我们提供了一种途径,而且丰富了更多的语义信息,在并行上会比朴素的for循环更有优势。


std::for_each

如需使用std::for_each,需要引入头文件:

#include <algorithm>

std::for_each函数定义:

template< class InputIt, class UnaryFunction >
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);

函数意义:按顺序应用给定的可调用对象f[first, last)范围内每个迭代器的结果

函数参数:

  • first、last:应用函数的范围
  • f:可调用对象,应用于范围[first, last]内每个迭代器的结果

对于可调用对象,其函数签名应等同于以下内容:

void fun(const Type &a);

其中,唯一参数也不一定要有const &,但该可调用对象的返回值必须为void

函数返回值:传入的可调用对象的最终状态(C++11后,该返回值为右值)

一般情况下,获得返回值常用于可调用对象为函数对象时(重载了()运算符类型的对象)。

根据语义,std::for_each可能的一种实现是:

template<class InputIt, class UnaryFunction>
constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
  for (; first != last; ++first) {
    f(*first);
  }
  return std::move(f);
}

std::for_each的优越性

std::for_each更明确了整个循环语义,有利于编译器优化。它偏向于函数式编程,就是老老实实从first迭代到end,没有中途退出循环的break,没有直接跳下一步循环的continue

这个语义清清楚楚,编译器可以尽情优化。相反,如果使用传统的for循环,或者C++11的range-based for,都无法让编译器相信半途中是否会来个break/continue这样的操作。

也就是说,编译器可以从for_each里获得更多的语义。而for循环把这些语义全搞丢了!

因此,std::for_each可以支持并行操作。C++17开始有并行的std::for_each重载了,目前msvc和gcc已经实现,clang还没有实现

template< class ExecutionPolicy, class ForwardIt, class UnaryFunction2 >
void for_each(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryFunction2 f);

该函数:应用给定的可调用对象f到[first, last)范围内每个迭代器的结果(不必按顺序),按照policy执行算法

policy指的是允许的并行类型,具体的类型种类可以参考:


std::for_each实例

#include <iostream>
#include <algorithm>
#include <vector>

class Sum {
 public:
  Sum() : sum(0) {}
  ~Sum() {}

  void operator()(int n) { sum += n; }
  int sum;
};

int main()
{
  std::vector<int> nums{6, 8, 4, 10, 2, 12};

  auto print = [](int n) {
    std::cout << n << " ";
  };

  std::for_each(nums.begin(), nums.end(), print);                   // 打印
  std::cout << std::endl;

  std::for_each(nums.begin(), nums.end(), [](int &n) {              // 每个数++
    ++n;
  });

  std::for_each(nums.begin(), nums.end(), print);                   // 打印
  std::cout << std::endl;

  Sum s = std::for_each(nums.begin(), nums.end(), Sum());           // 求和
  std::cout << s.sum << std::endl;

  int sum = 0;
  std::for_each(nums.begin(), nums.end(), [&sum](int n) {           // 求和
    sum += n;
  });
  std::cout << sum << std::endl;

  return 0;
}

编译并运行这段代码:

yngzmiao@yngzmiao-virtual-machine:~/test/foreach$ ./main 
6 8 4 10 2 12 
7 9 5 11 3 13 
48
48

相关阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值