C++标准库学习之 函数对象

在C++ 中存在一种比较怪异的用法,那就是使用一个对象当做函数,先看下面一个简单的例子

c 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

class Person{

public:
    void operator()(int element) const{
        std::cout<<element<<std::endl;
    }
};

int main(){

    Person p;

    std::vector<int> tsm={1,2,3,4,5,6,7,8,9};

    std::for_each(tsm.cbegin(),tsm.cend(),p);
    
  return 0;
}

这种用法就是在遍历过程中 将p 这个对象传入 for_earch 算法中,for_each 会调用 p 的 operator ()(int element) const; 方法,这个举动看起来有点怪异, 至于为什么要这么干, 原始是 Person 既然是一个对象,这个对象就可以拥有其他属性,如果这个属性是根据上下文关系计算出来的,我们在调用 他的 operator () 方法时,就能非常简单的使用这个他所拥有的这些属性,

在不使用函数对象时,如果我们需要遍历 for_earch ,打印他的信息该如何操作呢,看下面这个例子,我们使用 Lambda 表达式来完成这简单的操作

c 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

class Person{

public:
    void operator()(int element) const{
        std::cout<<element<<std::endl;
    }
};

int main(){
    std::vector<int> tsm={1,2,3,4,5,6,7,8,9};

    std::for_each(tsm.cbegin(),tsm.cend(),[](const int element){
        std::cout<<element<<std::endl;
    });
  return 0;
}

现在如果我们需要给这个 element 增加一个固定的 数值,并将这个算法修改为一个模板函数该如何写呢

c 复制代码
template<int value>
void addInt(int element){
    std::cout<<(element+value)<<std::endl;
}


int main(){
    std::vector<int> tsm={1,2,3,4,5,6,7,8,9};

    std::for_each(tsm.cbegin(),tsm.cend(),addInt<10>);
  return 0;
}

但是现在我们又遇到了另一种情况, 那就是这个10 是计算出来的结果, 但是由于 template< int value > 这种写法是将 value 变成了静态变量, 而我们计算出来的值又不是就使得这种模板的方式没有办法继续使用了,此时就轮到了 函数对象出场来拯救世界了,

c 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

class Person{

private:
    int value=0;

public:

    Person(int value):value(value){

    }

    void operator()(int element) const{
        std::cout<<(element+value)<<std::endl;
    }
};

int main(){
    int a=5;

    Person person(a);

    std::vector<int> tsm={1,2,3,4,5,6,7,8,9};

    std::for_each(tsm.cbegin(),tsm.cend(),person);
  return 0;
}

在C++ 标准库中介绍是这么描述函数对象的

在C++ 中定义了非常多的已定义函数在 < functional > 这个包下面,就像在上一篇中我们所写到的函数对象一样,他给我们带来了非常多的便利,我们都知道在 set 中所有的数据的排列都是有序的,那么我们如何更改这个排序呢,看下面例子

c 复制代码
#include <iostream>
#include <set>
#include "print.cpp"
#include <functional>


int main(){

    std::set<int,std::greater<int>>  tsm={1,3,5,7,9};

    PRENT_ELEMENT(tsm.cbegin(),tsm.cend());


    return 0;
}

结果:

vbnet 复制代码
D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
9
7
5
3
1

Process finished with exit code 0

如果将 greater 变成less 又会发生什么呢,

没错,就是按照从小到大的顺序排列

vbnet 复制代码
D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
1
3
5
7
9

Process finished with exit code 0

现在看到的仅仅只是针对int排序,如果针对一个class 来排序呢,看下面例子

c 复制代码
#include <iostream>
#include <set>
#include "print.cpp"
#include <functional>


class Tsm{

private:
public:
    int index;
    Tsm(int index):index(index){

    }
};

typedef  struct  TsmCompare{
    bool operator() (const Tsm& tsm1,const Tsm& tsm2){
        return tsm1.index < tsm2.index;
    }
};

int main(){
    std::set<Tsm,TsmCompare>  tsm;
    for (int i = 0; i < 10; ++i) {
        tsm.emplace(i);
    }
    std::for_each(tsm.cbegin(),tsm.cend(),[](const Tsm t){
       std::cout<<t.index<<std::endl;
    });
    return 0;
}

现在这个结构体 TsmCompare 他使用的是 < ,对应的是降序,如果使用 > 对应的就是升序,

我们现在使用的是一个普通的函数,如何将这个函数升级成为更高等级的函数呢, Binder 可以帮助我们来完成这个操作, Binder 可以将预定义函数对象其他数值结合到一起来使用,看下面这个例子

c 复制代码
#include <iostream>
#include <set>
#include "print.cpp"
#include <functional>
#include <deque>



int main(){

    std::set<int,std::greater<int>> tsm={5,1,3,4,2,6,9,7,8};

    std::deque<int> tsm2;

    PRENT_ELEMENT(tsm.cbegin(),tsm.cend());

    std::transform(tsm.begin(),tsm.end(),std::inserter(tsm2,tsm2.begin()),std::bind(std::multiplies<int>(),std::placeholders::_1,10));

    std::cout<<"------------------------"<<std::endl;

    PRENT_ELEMENT(tsm2.cbegin(),tsm2.cend());


    return 0;
}

我们先使用降序排列创建了一个set ,又创建了一个deque , 使用 transform 转换,遍历tsm ,在遍历的过程中使用 insertor 将数据插入到tsm2中,最后一个参数

c 复制代码
std::bind(std::multiplies<int(),std::placeholders::_1,10) 

他的写法就比较有意思了, 首先 bind 是一个函数,这个函数的作用是包裹其他函数, std::placeholders::_1 是一个占位符,在遍历的过程中拿到的 element 就会赋值给他,再使用 multiplies 做乘法,的结果就是遍历 start -> end ,每个位置都乘以 10

来看一下结果:

lua 复制代码
D:\CWorkSpace\tsmTest\cmake-build-debug\tsmTest.exe
9
8
7
6
5
4
3
2
1
------------------------
90
80
70
60
50
40
30
20
10

Process finished with exit code 0
相关推荐
qing_0406031 小时前
数据结构——二叉搜索树
数据结构·c++·二叉树·二叉搜索树
Ljw...2 小时前
DeepSeek+Kimi生成高质量PPT
数据库·c++·powerpoint·ppt·deepseek
敲上瘾2 小时前
基础dp——动态规划
java·数据结构·c++·python·算法·线性回归·动态规划
禁默2 小时前
C++之旅-C++11的深度剖析(1)
开发语言·c++
张有志_2 小时前
STL容器终极解剖:C++ vector源码级实现指南 | 从内存分配到异常安全的全流程避坑
c语言·c++·算法·开源·visual studio
挨代码3 小时前
UE_C++ —— Delegates
c++·ue
web_155342746564 小时前
性能巅峰对决:Rust vs C++ —— 速度、安全与权衡的艺术
c++·算法·rust
9毫米的幻想4 小时前
【Linux系统】—— 冯诺依曼体系结构与操作系统初理解
linux·运维·服务器·c语言·c++
Mr.Wang8094 小时前
条款23:宁以non-member、non-friend替换member函数
开发语言·c++
以卿a6 小时前
C++ 模板初阶
开发语言·c++