std::for_each、std::transform、std::for_each_n
1.for_each:应用函数到范围中的元素
for_each可以理解为一个for循环:依次对范围中的元素进行合法操作。
中文标准库:for_each
- 函数原型:
template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
//C++17起
template< class ExecutionPolicy, class ForwardIt, class UnaryFunction2 >
void for_each( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryFunction2 f );
//C++20起
template< class InputIt, class UnaryFunction >
constexpr UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
2.transform:将函数应用到某一范围各个元素,并在目标范围存储结果
- 函数原型:
//unary operation
template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform(InputIterator first1, InputIterator last1,OutputIterator result, UnaryOperation op);
//binary operation
template <class InputIterator1, class InputIterator2,class OutputIterator, class BinaryOperation>
OutputIterator transform(InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, OutputIterator result,BinaryOperation binary_op);
注意:transform输出参数(保存结果的参数)必须有足够的大小,可以使用resize重新分配大小,不能用reserve
3.transform和for_each的区别:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
{
std::vector<int> vec1{ 1,2,3,4,5 };
auto it = vec1.begin();
std::advance(it, 3);
std::for_each(vec1.begin(), it, [](int& i) {i = i * 2; });
std::for_each(vec1.begin(), vec1.end(), [](int& i) {return i * 2; }); //lambda表达式没有对vec1的元素进行修改,所以vec1没有变化
std::for_each(vec1.begin(), vec1.end(), [](int i) {return ++i; }); //值捕获,不会改变vec1
std::for_each(vec1.begin(), vec1.end(), [](int& i) {return ++i; }); //引用捕获,vec1 = {2,3,4}
std::for_each(vec1.begin(), vec1.end(), [](int& i) {i = -i; }); //vec1 = {-2,-3,-4}
}
{
std::vector<int> vec1{ 1,2,3,4,5 };
std::vector<int> vec2;
// 此处lambda的作用就是将vec1的每一个值乘2后赋值给vec2,对vec1并没有做任何修改
std::for_each(vec1.begin(), vec1.end(),
[&vec2](const int i) {
vec2.emplace_back(i*2);
});
}
{ // 以下代码和上面的lambda效果一模一样
std::vector<int> vec1{ 1,2,3,4,5 };
std::vector<int> vec2;
for (auto elem : vec1)
vec2.emplace_back(elem);
}
{
std::vector<int> vec1{ 1,2,3,4,5 };
std::vector<int> vec2;
vec2.resize(vec1.size());
std::transform(vec1.begin(), vec1.end(), vec2.begin(), [](int i) {return -i; }); //vec2 = {-1,-2,-3,-4,-5},vec2必须提前分配好大小
std::transform(vec1.begin(), vec1.end(), vec1.begin(), [](int i) {return -i; }); //vec1 = {-1,-2,-3,-4,-5}
//std::transform(vec1.begin(), vec1.end(), vec2.begin(), [](int& i) {++i; }); //报错:“ = ”: 无法从“void”转换为“int”,所以此处的函数对象必须有返回值,用来输出到vec2
}
return 0;
}
-
for_each参数中的函数对象不需要return一个值,而是将函数对象直接作用到传入的参数上,所以函数对象的lambda表达式一般都是引用捕获
-
transform是通过参数中的函数对象对传入的参数进行处理,然后存放在一个传入的容器中(可以是原操作容器),必须返回一个类型一致的值(用来存储结果)
-
std::transform 不保证按顺序应用 unary_op 或 binary_op 。为按顺序应用函数到数列,或应用修改序列元素的函数,应使用 std::for_each 。
4.for_each_n(C++17):应用一个函数对象到序列的前n个元素
- 函数原型
template< class InputIt, class Size, class UnaryFunction >
InputIt for_each_n( InputIt first, Size n, UnaryFunction f );
示例代码:
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> vec1{ 1,2,3,4,5 };
std::for_each_n(vec1.begin(), 3, [](auto& n) { n *= 2; });
//上下两种方法等价
std::vector<int> vec2{ 1,2,3,4,5 };
auto it = vec2.begin();
std::advance(it, 3);
std::for_each(vec2.begin(), it, [](int& i) {i *= 2; });
return 0;
}