【STL十四】函数对象(function object)_仿函数(functor)——lambda表达式

news2024/12/28 6:30:56

【STL十四】函数对象(function object)_仿函数(functor)——lambda表达式

  • 一、函数对象(function object)
  • 二、函数对象优点
  • 三、分类
  • 四、头文件
  • 五、用户定义函数对象demo
  • 六、std::内建函数对象
    • 1、 算术运算函数对象
    • 2、比较
    • 3、逻辑运算
    • 4、位运算
  • 七、lambda表达式
    • 1、简介
    • 2、作用
    • 3、定义
    • 4、最简单的demo
    • 5、标准用法
    • 6、变量捕获(capture clause)

一、函数对象(function object)

  • 定义:定义了一个operator()的对象,就叫函数对象(function object)。
  • 函数对象又被叫做仿函数(functor)。

注意:

  • 函数对象是一个类(or结构体、模板类),不是一个函数。
  • 函数对象重载“()”操作符,使得类可以像函数那样调用。

安装参数分
如果函数对象,有一个参数,叫一元函数对象。
如果函数对象,有二个参数,叫二元函数对象。
如果函数对象,有三个参数,叫多元函数对象。

二、函数对象优点

  • 函数对象通常不定义构造函数和析构函数,所以在构造和析构不会发生问题
  • 函数对象可以有自己的状态;(超出了普通函数的概念)
  • 模板函数对象使得函数对象具有通用性。

三、分类

  • 用户定义函数对象
  • std::内置函数对象
  • lambda表达式

四、头文件

  • 用户自己定义的函数无头文件,
  • std内建函数对象
    头文件如下
// 内置函数对象
#include<functional>

五、用户定义函数对象demo

  • Print就是函数对象
  • Print()(“HELLO WORLD”);//匿名函数对象
#include <iostream>
//
using namespace std;

class Print
{
public:
    void operator()(const char str[])
    {
        cout << str << endl;
    }
};

int main() {
    Print ob;

    ob("hello world");

    Print()("HELLO WORLD");//匿名函数对象
    
}

输出

hello world
HELLO WORLD

  • 函数对象可以有自己的状态?
    demo
#include <iostream>
//#include<functional>
using namespace std;

class Print
{
public:
    void operator()(const char str[])
    {
        cout << str << endl;
        m_sum++;
    }
    int m_sum = 0;
};

int main() {
    Print ob;

    ob("hello world");
    ob("hello jx");
    cout << ob.m_sum << endl;
    
}

输出

hello world
hello jx
2

  • 当然以上你可以写成模板,or同时重载int类型的,都是可以的

    • 重载int类型的
#include <iostream>
//#include<functional>
using namespace std;

struct Print
{
public:
    void operator()(const char str[])
    {
        cout << str << endl;
    }
    void operator()(int num)
    {
        cout << num << endl;
    }
};

int main() {
    Print ob;

    ob("hello world");

    Print()("HELLO WORLD");

    ob(110);
    
}
  • 模板函数对象使得含对象具有通用性?
    • 模板
#include <iostream>
#include<string>
using namespace std;

template<typename T>
class Print
{
public:
    void operator()(T temp)
    {
        cout << temp << endl;
        m_sum++;
    }
    int m_sum = 0;
};

int main() {
    Print<string> ob;

    ob("hello world");
    ob("hello jx");
    cout << ob.m_sum << endl;
    
    Print<int> ob2;
    ob2(123);
    ob2(123);
}

输出

hello world
hello jx
2
123
123

六、std::内建函数对象

  • stl内建了一些函数对象,分为算术运算、比较、逻辑运算、位运算;
  • 其实,这些内建函数对象,都是配合容器和算法使用的,但是我们还没有讲解郭算法,所以做个不设计算法的简单的demo.

1、 算术运算函数对象

  • 1.1、分类
    在这里插入图片描述
  • 1.2、demo
#include <iostream>
#include<functional>
using namespace std;

int main() {
    std::plus<int>  add;
    cout << "add(2, 3) = " << add(2, 3) << endl; //2+3 = 5

    std::minus<int> sub;
    cout << "sub(2, 3) = " << sub(2, 3) << endl; //2-3 = -1

    std::multiplies<int> mul;
    cout << "mul(2, 3) = " << mul(2, 3) << endl; //2*3 = 6

    std::divides<int> div;
    cout << "div(2, 3) = " << div(2, 3) << endl; //2/3 = 0

    std::modulus<int> mod;
    cout << "mod(2, 3) = " << mod(2, 3) << endl; //2%3 = 2

    std::negate<int> neg;
    cout << "neg(2) = " << neg(2) << endl; //neg(2) = -2 
        
}

输出

add(2, 3) = 5
sub(2, 3) = -1
mul(2, 3) = 6
div(2, 3) = 0
mod(2, 3) = 2
neg(2) = -2

2、比较

  • 2.1、分类
    在这里插入图片描述
  • 2.2、demo
#include <iostream>
#include<functional>
using namespace std;

int main() {
    std::equal_to<int> ob1;
    cout << "ob1(1, 2) = " << ob1(1, 2) << endl;

    std::not_equal_to<int> ob2;
    cout << "ob2(1, 2) = " << ob2(1, 2) << endl;

    std::greater<int> ob3;
    cout << "ob3(1, 2) = " << ob3(1, 2) << endl;

    std::less<int> ob4;
    cout << "ob4(1, 2) = " << ob4(1, 2) << endl;

    std::greater_equal<int> ob5;
    cout << "ob5(1, 2) = " << ob5(1, 2) << endl;

    std::less_equal<int> ob6;
    cout << "ob6(1, 2) = " << ob6(1, 2) << endl;
}

输出

ob1(1, 2) = 0
ob2(1, 2) = 1
ob3(1, 2) = 0
ob4(1, 2) = 1
ob5(1, 2) = 0
ob6(1, 2) = 1

3、逻辑运算

  • 3.1、分类
    在这里插入图片描述
  • 3.2、demo
#include <iostream>
#include<functional>
using namespace std;

int main() {
    std::logical_and<bool> l_and;
    cout << "l_and(1, 0) = " << l_and(1, 0) << endl;

    std::logical_or<int> l_or;
    cout << "l_or(1, 0) = " << l_or(1, 0) << endl; 

    std::logical_not<int> l_not;
    cout << "l_not(2) = " << l_not(2) << endl; 
}

输出

l_and(1, 0) = 0
l_or(1, 0) = 1
l_not(2) = 0

4、位运算

  • 4.1、分类
    在这里插入图片描述
    • demo
  • 1、“与” 运算(&):只有两个位都是1的时候结果才是1,否则是0;如1&1=1,1&0=0,0&1=0,0&0=0
  • 2、“或” 运算(|):只要有一个是1,结果就是1。如:1|0=1,0|1=1,1|1=1,0|0=0
  • 3、“异或” 运算(^):相同为0,不同为1;0|0=0,0|1=1,1|0=1,1|1=0
  • 4、取反运算(~):就是0=1,1=0
#include <iostream>
#include<functional>
using namespace std;

int main() {
    std::bit_and<int> b_and;
    cout << "b_and(1, 2) = " << b_and(1, 2) << endl;

    std::bit_or<int> b_or;
    cout << "b_or(1, 2) = " << b_or(1, 2) << endl;

    std::bit_xor<int> b_xor;
    cout << "b_xor(2,3) = " << b_xor(2,3) << endl;

    std::bit_not<bool> b_not;
    cout << "b_not(1) = " << b_not(1) << endl;
}

输出

b_and(1, 2) = 0
b_or(1, 2) = 3
b_xor(2,3) = 1
b_not(1) = 1

bit_not有问题,因为bool的取反,应该是0,但是输出是1,原因未知;

七、lambda表达式

使用 STL 时,往往会大量用到函数对象,为此要编写很多函数对象类。有的函数对象类只用来定义了一个对象,而且这个对象也只使用了一次,编写这样的函数对象类就有点浪费。
而且,定义函数对象类的地方和使用函数对象的地方可能相隔较远,看到函数对象,想要查看其 operator() 成员函数到底是做什么的也会比较麻烦。

  • 对于只使用一次的函数对象类,能否直接在使用它的地方定义呢?Lambda 表达式能够解决这个问题。使用 Lambda 表达式可以减少程序中函数对象类的数量,使得程序更加优雅。

1、简介

  • lambda expressions = lambda表达式(也叫闭包——Colsure)
  • lambda表达式也是匿名函数对象
  • lambda表达式也是一种仿函数、

2、作用

  • 很方便的定义函数、并被别的函数调用。

3、定义

Lambda 表达式的定义形式如下:

[]中括号里面是一下捕获变量,或者为空。

[捕获变量] (参数表) -> 返回值类型
{
   函数主体
}

auto f=[](int a, int b) ->int
{
return a+b;
};

“捕获变量”可以是=或&,表示{}中用到的、定义在{}外面的变量在{}中是否允许被改变。=表示不允许,&表示允许。当然,在{}中也可以不使用定义在外面的变量。“-> 返回值类型”可以省略。

4、最简单的demo

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

int main() {
    auto f = [](int a, int b)
    {
        return a < b;
    };

    cout << f(2, 3);
}

输出

1

5、标准用法

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

int main() {
   // 定义lambda表达式,不使用变量捕获
    auto f = [](int a, int b) ->int
    {
        return a + b;
    };
    cout << f(1, 2) << endl;
}

输出

3

6、变量捕获(capture clause)

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

int main() {
    int M = 10;
    int N = 3;

    auto f = [&M, N](int a) ->int
    {
        M = 20;
        return N*a;
    };
    cout << f(3) << endl;
    cout << M << endl;
}

输出

9
20

  • 变量捕获:就是方括号中的部分,让我们的匿名函数可以访问、甚至修改函数外部的变量。
  • 如果是空,表示不捕获任何变量。
  • [&M]——如果变量前有引用&,则是按引用捕获——可以修改外围变量的值。
  • [M]——如果变量前没引用&,则是按值捕获——不可以修改外围变量的值。
  • [&]——只写引用,按照引用捕获所有的封闭范围中的变量;
  • [=]——只写等号,所有变量都按值捕获;
  • [&, = M]——单独制定一些变量按照值捕获,其他变量按照引用捕获;
  • [this]——如果在某个class中使用匿名函数,可以使用this捕获当前实例的指针。
  • c++17后还可以使用[*this]按值捕获该实例。
  • c++14后,可以在捕获语句中定义新的变量,并初始化。(这些变量无需出现在匿名函数外围环境中)
auto f = [&M, N, k=5](int a) ->int
    {
        M = 20;
        return N*a*k;
    };
  • c++14后,参数列表支持auto类型
[](auto a, auto b){return a+b;}

参考:
1、C++ STL 容器库 中文文档
2、STL教程:C++ STL快速入门
3、https://www.apiref.com/cpp-zh/cpp/header.html
4、https://en.cppreference.com/w/cpp/container
5、哔哩哔哩_HexUp_清晰易懂,现代C++最好用特性之一:Lambda表达式用法详解
6、WIKI教程_C ++标准库_C++ Library - <iterator>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/462872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YARN 远程代码执行(RCE)安全漏洞问题分析与解决方案

YARN 远程代码执行&#xff08;RCE&#xff09;安全漏洞问题分析与解决方案 1 YARN RCE 漏洞问题问题现象 某客户使用Tenable.sc扫描安全漏洞后反馈&#xff0c;YARN 存在Remote code execution (RCE) 安全漏洞问题&#xff0c;攻击者可在未经过身份验证的情况下通过该漏洞在…

【21】核心易中期刊推荐——人工智能 | 遥感图像识别

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…

psql在建表时,分为常规、外部、分区,三者有什么区别?如何从建表语句中区分?

在 PostgreSQL 中&#xff0c;常规表、外部表和分区表都可以通过 CREATE TABLE 语句进行创建&#xff0c;它们的创建语法略有不同&#xff0c;通过创建语句可以很明显地区分它们的类型。 以下是常规表、外部表和分区表的创建语法及示例&#xff1a; 1. 常规表 常规表是最常见…

Spring核心与设计思想、创建与使用

文章目录 一、Spring是什么二、为什么要学习框架三、IoC和DI&#xff08;一&#xff09;IoC1. 认识IoC2. Spring的核心功能 &#xff08;二&#xff09;DI 四、Spring项目的创建&#xff08;一&#xff09;使用 Maven 方式创建一个 Spring 项目 五、Spring项目的使用&#xff0…

少年与阿童木:一场软件竞技赛背后的智能未来

1961年&#xff0c;手冢治虫创办了虫制作株式会社&#xff0c;带领团队开始尝试将此前的漫画作品进行动画化。1963年的元旦&#xff0c;他们的首部作品一经播出就引发轰动&#xff0c;这部动画的名字叫做——《铁臂阿童木》。 一晃数十年&#xff0c;阿童木已经成为了几代人对A…

2023年6月DAMA-CDGA/CDGP数据治理工程师认证报名及费用

目前6月DAMA-CDGA/CDGP数据治理认证考试开放报名地区有&#xff1a;北京、上海、广州、深圳、长沙、呼和浩特。目前南京、济南、西安、杭州等地区还在接近开考人数中&#xff0c;打算6月考试的朋友们可以抓紧时间报名啦&#xff01;&#xff01;&#xff01; 5月初&#xff0c;…

大数据 | 实验二:文档倒排索引算法实现

文章目录 &#x1f4da;实验目的&#x1f4da;实验平台&#x1f4da;实验内容&#x1f407;在本地编写程序和调试&#x1f955;代码框架思路&#x1f955;代码实现 &#x1f407;在集群上提交作业并执行&#x1f955;在集群上提交作业并执行&#xff0c;同本地执行相比即需修改…

蓝牙耳机怎么挑选?鹏鹏数码盘点2023口碑蓝牙耳机排行榜

大家好&#xff0c;欢迎来到鹏鹏数码频道。 上次测评发布后网友们评论不知道蓝牙耳机怎么挑选&#xff0c;为此我购入了市面上主流品牌的蓝牙耳机共计三十款&#xff0c; 经过两周的地狱式测评&#xff0c;总结了口碑蓝牙耳机排行榜&#xff0c;看看表现最好的是哪几款蓝牙耳机…

Linux操作系统命令大全

Linux是一种操作系统 Operating System 简称 OS &#xff0c;是软件的一部分&#xff0c;它是硬件基础上的第一层软件&#xff0c;是硬件和其它软件沟通的桥梁。 操作系统会控制其他程序运行&#xff0c;管理系统资源&#xff0c;提供最基本的计算功能&#xff0c;如管理及配置…

SSM整合(一) | SSM创建项目配置整合 - 添加功能模块

文章目录 SSM整合SSM配置整合SSM功能模块 SSM整合 SSM配置整合 SSM整合流程: 创建工程SSM整合 Spring SpringConfig MyBatis MybatisConfigJdbcConfigjdbc.properties SpringMVC ServletConfigSpringMvcConfig 创建工程 基于Maven创建项目, 选择webapp模版并补全缺失的目录 …

最优化方法Python计算:一元函数导数的数值计算

定义1 给定连续函数 f ( x ) f(x) f(x)&#xff0c; x ∈ Ω ⊆ R x\in\Omega\subseteq\text{ℝ} x∈Ω⊆R。设 x , x 1 ∈ Ω x,x_1\in\Omega x,x1​∈Ω&#xff0c; Δ x x − x 1 \Delta xx-x_1 Δxx−x1​ 称为变量 x x x的差分。此时&#xff0c; x x 1 Δ x xx_1\De…

黑盒测试过程中【测试方法】详解5-输入域,输出域,猜错法

在黑盒测试过程中&#xff0c;有9种常用的方法&#xff1a;1.等价类划分 2.边界值分析 3.判定表法 4.正交实验法 5.流程图分析 6.因果图法 7.输入域覆盖法 8.输出域覆盖法 9.猜错法 黑盒测试过程中【测试方法】讲解1-等价类&#xff0c;边界值&#xff0c;判定表_朝一…

Linux下实现共享内存的两种机制(附源码)

START Hello 大家好。 今天来讲一下Linux进程通信中重要的通信方式&#xff1a;共享内存作为Linux软件开发攻城狮&#xff0c;进程间通信是必须熟练掌握的重要技能&#xff0c;而共享内存是在程序开发中常用的也是重要的一种进程间通信方式。 下面我们就来聊一聊Linux下进程间…

【C++】string类的深浅拷贝问题

string类的深浅拷贝问题 浅拷贝问题构造/析构函数拷贝构造/赋值运算符重载的多种写法 浅拷贝问题 我们知道&#xff0c;定义一个类的时候&#xff0c;如果我们没有写构造&#xff0c;拷贝构造&#xff0c;赋值运算符重载&#xff0c;析构方法的话&#xff0c;编译器会自动生成。…

Django学习笔记001之创建项目

学习目标&#xff1a; 了解前端后台框架 掌握vs搭建Django环境 学习内容 1.背景学习 优缺点&#xff1a; 2.vs搭建Django开发环境 2.1. 准备vscode工具 可以从github上获取&#xff1a;https://github.com/microsoft/vscode。 2.2. 构建python虚拟环境 使用的命令是pyth…

微分方程数值解法(Runge-Kutta法PLC实现)

微分方程数值解法之欧拉法请参看下面的博客文章: 微分方程数值解法(PID仿真用一阶被控对象库PLC算法实现)_数学微积分算法plc编程实例_RXXW_Dor的博客-CSDN博客微分方程除极特殊情况外,大部分不可能求出它的精确解,只能用各种近似方法得到满足一定精度的近似解,微分方程由…

CTA进网检验要求修订原则和变更说明 SAR新国标在2024年正式实施

《进网检验要求文件》 实行定期及动态更新原则&#xff0c;其中检测项目应能体现进网监管的职责定位。 第一部分 基本功能性能 第二部分 空间性能 SAR 新版进网检验要求细化了各场景的测试距离&#xff1a; SAR新要求的实施日期&#xff1a; 第二部分 空间性能 EMC 第二部分 空…

【MySQL】查询中,NULL值转换为空字符串

系列文章 C#底层库–MySQLBuilder脚本构建类&#xff08;select、insert、update、in、带条件的SQL自动生成&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类&#xff08;推荐阅读&#xff0…

【browserify】一步步教你学会browserify

https://www.cnblogs.com/fsg6/p/13139627.html Browserify browserify的官网是http://browserify.org/&#xff0c;他的用途是将前端用到的众多资源&#xff08;css,img,js,…) 打包成一个js文件的技术。 比如在html中引用外部资源的时候&#xff0c;原来我们可能这样写 &l…

C嘎嘎~~ [类 上篇]

类 上篇 1.面向过程和面向对象的认识2.类的引入3.类的定义4.类的访问限定符和封装4.1封装4.2访问限定符 5.类的作用域 1.面向过程和面向对象的认识 面向过程 和 面向对象的区别: 面向过程关注的是过程, 而面向对象关注的是对象之间的关系, 交互. C语言是面向过程的, 而C是面向对…