当前位置: 首页 > news >正文

(1)STL算法之遍历容器

1、for_each()  遍历容器

在实现遍历的基础上,利用参数三(仿函数)实现其他操作,仅遍历打印,或者遍历更改容器值。

【原型】

template <class InputIterator, class Function>

Function for_each (InputIterator first,  InputIterator last,  Function fn);   

参数一:迭代器   

参数二:迭代器      

参数三:仿函数(也可以叫 函数对象)

#include <iostream>   
#include <algorithm>    // std::for_each
#include <vector>      

void myfunction(int i) {  // function:   仅遍历打印容器内的值
    std::cout << ' ' << i;
}

struct myclass {           // function object type:
    void operator() (int i)     //仅遍历打印容器内的值
    {
        std::cout << ' ' << i; 
    }
} myobject;

int main() 
{
    std::vector<int> myvector;
    myvector.push_back(10);
    myvector.push_back(20);
    myvector.push_back(30);

    std::cout << "myvector contains:";
    for_each(myvector.begin(), myvector.end(), myfunction);
    std::cout << '\n';

    // or
    std::cout << "myvector contains:";
    for_each(myvector.begin(), myvector.end(), myobject);
    std::cout << '\n';
    return 0;
}

对于参数3 函数如何调用的问题,我疑惑了很久,今天百度了很长时间,然后想起来看源码,忽然就有点明白了。

for_each()源码

// FUNCTION TEMPLATE for_each
template <class _InIt, class _Fn>
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func)  // perform function for each element [_First, _Last)
{   
     _Adl_verify_range(_First, _Last);
    auto _UFirst      = _Get_unwrapped(_First);  // 获取 first 迭代器指向的地址
    const auto _ULast = _Get_unwrapped(_Last);   // 获取 Last 迭代器指向的地址

    for (; _UFirst != _ULast; ++_UFirst)     // 放入一个for 循环,遍历容器中所有值的地址
    {
        _Func(*_UFirst);  // * _UFirst 拿出此地址的值,作为参数,传递到参数3 中 
    }

    return _Func;    //返回函数对象的最终状态
}

 

以下示例来自用户文章:C++for_each()的返回值,使用for_each的返回值,获取1-100的总和,

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*
    for_each()它可以返回其仿函数(返回所传入的函数对象的最终状态).
    这样我们就可以通过for_each()的返回值来获取仿函数的状态.
*/

class CSum
{
public:
    CSum(){
        m_sum = 0;
    }
    void operator()(int n)/* 仿函数 */{
        m_sum += n;
    }

    int GetSum() const{
        return m_sum;
    }

private:
    int m_sum;
};

int main()
{
    vector<int> vi;
    for (int i = 1; i <= 100; i++)
    {
        vi.push_back(i);
    }
    //通过for_each返回值访问其最终状态(返回所传入的函数对象的最终状态).
    CSum cs = for_each(vi.begin(), vi.end(), CSum());//最后一个参数相当于用CSum创建了一个无参对象
    cout << cs.GetSum() << endl;

    return 0;
}

 

 

在for_each()的基础之上,通过仿函数类,使容器内的元素  * 2

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

template <class T>
void FillValue(T& vect, int first, int last){   // 初始化容器
    if (last >= first){
        for (int i = first; i <= last; ++i)
            vect.insert(vect.end(), i);
    }
}

void print(int elem){        // 函数对象
    cout << elem << " ";
}

template <class T>
class Multiple {       // 仿函数类,
private:
    T theValue;
public:
    Multiple(const T& v) : theValue(v)
    {
    }
    void operator()(T& elem) const   // 重载 (),使类具有类似函数的行为,就是仿函数类
    {
        elem *= theValue;    // * theValue
    }
};

void main()
{
    vector <int> myvector;
    FillValue(myvector, 1, 10);   // 给容器赋值 1-10
    for_each(myvector.begin(), myvector.end(), print);  //  仅遍历 打印
    cout << endl;
    for_each(myvector.begin(), myvector.end(), Multiple<int>(2));  //遍历 更改 容器值
    for_each(myvector.begin(), myvector.end(), print);
    cout << endl;
}

对以上示例中的class Multiple 仿函数类(该名词出现在《C++STL标准程序库设计指南》),作者的解释是:在类中实现函数operator(),之后这个类就有了类似函数的行为,就是一个仿函数类。

仿函数:《C++标准程序库》的解释是:仿函数是泛型编程强大威力和纯粹抽象概念的又一例证。可以说,任何东西,只有其行为像函数,他就是一个函数,因此如果你定义了一个对象,行为像函数,它就可以当做函数来使用。

那么什么才算具备函数行为呢?所谓函数行为,是指可以使用圆括号传递参数,借以调用某个东西。重载()即可。

相关文章:

  • (2)STL算法之元素计数
  • (3)STL算法之搜索
  • STL算法
  • (4)STL算法之比较
  • linux中实现线程同步的6种方法
  • Linux TCP通信示例
  • QtTCP通信示例
  • (5)STL算法之复制
  • (6)STL算法之转换
  • (7)STL算法之交换赋值
  • 菱形继承问题
  • 改善程序与设计的N个做法
  • C++数据结构之顺序表
  • C++数据结构之单链表
  • (8)STL算法之替换
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【刷算法】从上往下打印二叉树
  • Cookie 在前端中的实践
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Effective Java 笔记(一)
  • HTML中设置input等文本框为不可操作
  • linux安装openssl、swoole等扩展的具体步骤
  • Object.assign方法不能实现深复制
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • Vue UI框架库开发介绍
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 关于extract.autodesk.io的一些说明
  • 和 || 运算
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​第20课 在Android Native开发中加入新的C++类
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • (Java)【深基9.例1】选举学生会
  • (翻译)terry crowley: 写给程序员
  • (四)库存超卖案例实战——优化redis分布式锁
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (原創) 物件導向與老子思想 (OO)
  • (转) Face-Resources
  • (转)菜鸟学数据库(三)——存储过程
  • ./configure,make,make install的作用(转)
  • .bashrc在哪里,alias妙用
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .bat批处理(一):@echo off
  • .net 调用php,php 调用.net com组件 --
  • .NET 反射 Reflect
  • .Net8 Blazor 尝鲜
  • .net对接阿里云CSB服务
  • .NET建议使用的大小写命名原则
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...
  • ::前边啥也没有
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(白虎组)
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决