【STL】for_each()算法

11 篇文章 0 订阅

【STL】for_each()算法

一、for_each()概述

  • for_each()算法非常灵活,允许你以不同的方式访问、处理、修改每一个元素
  • 因此,for_each()既属于非更易型算法,又属于更易型算法
  • 备注:自C++11起,range-based for循环提供了更方便更自然的行为。因此,for_each()可能逐渐降低其重要性

二、for_each()语法

在这里插入图片描述

  • 头文件:<algorithm>
  • 相关语法:
    • 对区间[beg,end)中的每一个元素调用op(elem)
    • 返回op(它已在算法内部被改动过)的一个拷贝(副本)。C++11起,op的返回值被移动
    • op可以改动元素。然而,请参考与transform()之间的比较,后者具有相同能力,但行事稍有不同
    • op的任何返回值都会被忽略
  • 复杂度:线型。调用op()共numElems次
  • for_each()的实现如下:
    在这里插入图片描述

三、for_each()的非更易型使用案例

演示案例①
例如下面调用for_each打印vector中的每一个元素,其参数3传递的是一个lambda

int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
 
    for_each(vec.begin(), vec.end(), 
        [](int elem) {std::cout << elem << " "; }
    );
}

在这里插入图片描述

演示案例②
当然,你可以可以向参数3传递一个函数用来打印元素:

void print(int elem)
{
    std::cout << elem << " ";
}
 
int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
    for_each(vec.begin(), vec.end(), print);
}

在这里插入图片描述

演示案例③

  • 我们也可以为其传入一个函数对象
  • 下面的参数3创建一个print临时对象op传递给for_each(),然后每次调用op(int elem)打印元素
class print
{
public:
    void operator()(int elem)
    {
        std::cout << elem << " ";
    }
};
 
int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
	
    //创建一个print临时对象传递给for_each()
    for_each(vec.begin(), vec.end(), print());
}

在这里插入图片描述

演示案例④
C++11,起,你可以使用range-based for循环完成上面的功能,且更加方便

int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
    for(const auto & elem:vec)
    {
        std::cout << elem << " ";
    }
}

在这里插入图片描述

四、for_each()的更易型使用案例

演示案例①

  • 我们调用向for_each()算法的参数3传入一个lambda,lambda的参数为引用类型,那么每次传入给lambda的将会是vector的每个元素的引用,然后在lambda内部改变vector的元素:
int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
 
    //改变每个元素的值
    for_each(vec.begin(), vec.end(),
        [](int& elem) {elem += 10; }
    );
 
    //打印
    for (const auto & elem : vec)
    {
        std::cout << elem << " ";
    }
}

在这里插入图片描述

演示案例②

  • 如果我们还想让lambda每次运行时,让其每个元素的值加上第一个元素的值,那么可以在lambda使用[=]形式
int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
    for (const auto & elem : vec)
    {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
 
    for_each(vec.begin(), vec.end(),
        [=](int& elem) {elem += *(vec.begin()); }
    );
 
    for (const auto & elem : vec)
    {
        std::cout << elem << " ";
    }
}
  • 结果如下图所示:
    • lambda的[]内使用的是=号,因此传入的是vec.begin()的拷贝
    • 其中vec.begin()等于1,每次每个元素每次都加上1,最终的结果如下图所示
      在这里插入图片描述

演示案例③

int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
    for (const auto & elem : vec)
    {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
 
    for_each(vec.begin(), vec.end(),
        [&](int& elem) {elem += *(vec.begin()); }
    );
 
    for (const auto & elem : vec)
    {
        std::cout << elem << " ";
    }
}
  • 结果如下图所示:
    • lambda的[]内使用的是&号,因此传入的是vec.begin()的引用
    • 第一次for_each()之后,vec.begin()等于2,之后每个元素每次都加上2,最终的结果如下图所示

在这里插入图片描述

演示案例④

  • 我们也可以为其传入一个函数对象给它
  • 下面也是构造一个AddValue临时对象op给for_each(),但是由于AddValue的构造函数需要一个函数,因此给出一个数值构造临时对象。然后每次op(int &elem),将数值+=
template<typename T>
class AddValue
{
private:
    T theValue;
public:
    AddValue(const T& v) :theValue(v) {}
    void operator()(T& elem)
    {
        elem += theValue;
    }
};
 
int main()
{
    std::vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
	
    //构造一个AddValue临时对象给for_each()
    for_each(vec.begin(), vec.end(), AddValue<int>(10));
    for (const auto & elem : vec)
    {
        std::cout << elem << " ";
    }
}

在这里插入图片描述

五、for_each()的返回值

  • 通过for_each()的语法我们知道,for_each()的返回值为参数3的一个拷贝

演示案例

  • 代码如下:
class MeanValue
{
private:
    long num;
    long sum;
public:
    MeanValue() :num(0), sum(0) {}
    void operator()(int elem)
    {
        num++;
        sum += num;
    }
 
    operator double()
    {
        return static_cast<double>(sum) / static_cast<double>(num);
    }
};
 
int main()
{
    vector<int> coll{ 1,2,3,4,5,6,7,8 };
 
    //返回一个MeanValue()对象的拷贝,但是由于MeanValue支持operator double,因此我们可以直接将MeanValue转换为一个double类型返回
    double mv = for_each(coll.begin(), coll.end(), MeanValue());
    std::cout << "mean value: " << mv;
}
  • 代码解析:

    • 下面我们创建一个临时MeanValue()对象给for_each(),那么每次for_each()运算的时候都会调用这个临时对象的operator()运算符,之后将MeanValue()临时对象返回
    • 又因为MeanValue()类型定义了operator double(),因此我们可以将一个MeanValue()对象转换为一个double类型,因此直接用double数据作为for_each()的返回值接收者
  • 结果如下所示:
    在这里插入图片描述

  • 这个演示案例在“函数对象”一文中也介绍过,稍有不同,但是原理一致:https://blog.csdn.net/qq_41453285/article/details/105486284

  • 也可以使用lambda完成任务(详情见文章:https://blog.csdn.net/qq_41453285/article/details/105486309),并以by reference方式传递返回值。然而在这种情形下lambda不见得比较好,因为function object不但封装sum作为其内部状态,也封装了“sum除以元素个数”这一最终触发

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值