浅谈STL|STL函数对象篇

在这里插入图片描述

一.函数对象概念

概念:

·重载函数调用操作符的类,其对象常称为函数对象
·函数对象使用重载的()时,行为类似函数调用,也叫仿函数

本质:

函数对象(仿函数)是一个类,不是一个函数

特点

  • 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值;
  • 函数对象超出普通函数的概念,函数对象可以有自己的状态;
  • 函数对象可以作为参数传递;

函数对象可以像普通函数一样被调用,并且可以接受参数和返回值。通过重载函数调用操作符 operator(),函数对象可以在使用时表现得像函数一样。

函数对象的一个优势是它可以拥有自己的状态。由于函数对象实际上是一个类的对象,所以它可以拥有成员变量,这些变量可以在每次调用时保持状态并进行更新。这使得函数对象可以在多次调用之间维护一些信息。

此外,函数对象还可以作为参数传递给其他函数。许多标准库的算法函数,例如 std::sortstd::transform 等,可以接受函数对象作为参数,以定义算法的具体操作。通过将函数对象传递给其他函数,我们可以实现更灵活、可定制的功能。

以下是一个简单的示例,展示了函数对象的用法:

#include <iostream>class MyFunctor
{
public:void operator()(int x) const{// 在回调时输出消息std::cout << "Function object called with " << x << std::endl;}
};void callWithFunctor(const MyFunctor& functor, int value)
{functor(value);  // 调用函数对象
}int main()
{MyFunctor functor;callWithFunctor(functor, 42);  // 传递函数对象给函数,并进行调用return 0;
}

在上述示例中,MyFunctor 是一个函数对象,我们将它作为参数传递给 callWithFunctor 函数,并在函数内部调用函数对象。

总结来说,函数对象可以像普通函数一样被调用,可以接受参数和返回值,可以拥有自己的状态,并可以作为参数传递给其他函数,这使得函数对象在编程中非常有用和灵活。


函数对象相比于普通函数具有一个重要的优势,那就是函数对象可以拥有自己的状态。这意味着函数对象可以在多次调用之间记录和维护自己的内部数据。

普通函数是无状态的,它们不会保留任何关于之前调用的信息。每次调用函数时,它们只是根据传入的参数执行相应的操作,并返回结果。

而函数对象则可以在每次调用时保持状态,并根据状态的变化来改变行为。这种状态是通过函数对象的成员变量来实现的。函数对象的成员变量可以记录在调用过程中需要持久化的数据,而这些数据会在不同的函数调用之间持续存在。

这种函数对象的状态可以非常有用。它允许我们在不同的调用之间共享和利用数据,从而实现更复杂的行为。例如,我们可以使用函数对象来实现一个计数器,每次调用增加计数值,并在后续的调用中使用该值。

以下是一个简单的示例,展示了函数对象中保存状态的功能:

#include <iostream>class Counter
{
public:Counter() : count(0) {}int operator()(){return ++count;}private:int count;
};int main()
{Counter counter;std::cout << counter() << std::endl;  // 输出:1std::cout << counter() << std::endl;  // 输出:2std::cout << counter() << std::endl;  // 输出:3return 0;
}

在上述示例中,Counter 是一个函数对象,它通过重载函数调用操作符 operator() 来实现计数的功能。每次调用 Counter 对象时,计数器的值会增加,并返回新的计数值。

总结而言,函数对象相比普通函数具有自己的状态,这使得它们可以在多次调用之间保持数据,并根据状态的变化改变行为。这种功能使得函数对象在许多应用场景中非常有用,例如实现计数器、缓存等。

二.谓词

概念:

  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数,那么叫做一元谓词
  • 如果operator()接受两个参数,那么叫做二元谓词

返回 bool 类型的仿函数被称为谓词(Predicate)。谓词通常用于对某些条件进行判断,并返回相应的布尔值。

此外,根据 operator() 接受的参数数量,可以将谓词进一步分类为一元谓词(Unary Predicate)和二元谓词(Binary Predicate)。

  • 一元谓词是指 operator() 只接受一个参数的谓词。它用于对单个对象进行判断,返回一个布尔值。一元谓词通常用于像 std::find_ifstd::remove_if 等算法中。
  • 二元谓词是指 operator() 接受两个参数的谓词。它用于对两个对象进行比较或判断,返回一个布尔值。二元谓词通常用于像 std::sortstd::find 等算法中,用于指定排序规则或比较条件。

通过使用谓词,我们可以灵活地对对象进行条件判断和过滤。

以下是一个简单的示例,展示了一元谓词和二元谓词的概念:

#include <iostream>
#include <vector>
#include <algorithm>// 一元谓词
struct IsEven
{bool operator()(int n) const{return n % 2 == 0;}
};// 二元谓词
struct IsLess
{bool operator()(int a, int b) const{return a < b;}
};int main()
{std::vector<int> numbers = { 1, 2, 3, 4, 5 };// 使用一元谓词查找第一个偶数auto it = std::find_if(numbers.begin(), numbers.end(), IsEven());if (it != numbers.end()){std::cout << "First even number: " << *it << std::endl;}// 使用二元谓词排序std::sort(numbers.begin(), numbers.end(), IsLess());// 输出排序结果std::cout << "Sorted numbers: ";for (int num : numbers){std::cout << num << " ";}std::cout << std::endl;return 0;
}

在上述示例中,IsEven 是一个一元谓词,通过重载 operator() 来判断一个数字是否为偶数。IsLess 是一个二元谓词,通过重载 operator() 实现了两个数字的比较操作。

我们在主函数中使用了一元谓词来查找第一个偶数,并使用二元谓词对数组进行排序。

总结来说,返回 bool 类型的函数对象被称为谓词。根据 operator() 接受的参数数量,谓词可以进一步分类为一元谓词和二元谓词。谓词在标准库的算法中大量使用,用于自定义比较和条件判断。


find_if

std::find_if 是 C++ 标准库中的一个算法函数,它的作用是在给定的范围内查找满足指定条件的元素,并返回第一个满足条件的元素的迭代器。

函数签名如下所示:

template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);

参数说明:

  • firstlast:表示要查找的元素范围,first 表示范围的起始位置,last 表示范围的结束位置(不包含在范围内)。
  • p:一个一元谓词,用于判断元素是否满足条件。

函数返回值是一个迭代器,指向范围内第一个满足条件的元素,如果没有找到满足条件的元素,则返回 last

以下是一个简单的示例,展示了 std::find_if 的使用:

#include <iostream>
#include <vector>
#include <algorithm>struct IsEven
{bool operator()(int n) const{return n % 2 == 0;}
};int main()
{std::vector<int> numbers = { 1, 2, 3, 4, 5 };// 使用一元谓词查找第一个偶数auto it = std::find_if(numbers.begin(), numbers.end(), IsEven());if (it != numbers.end()){std::cout << "First even number: " << *it << std::endl;}return 0;
}

在上述示例中,我们定义了一个一元谓词 IsEven,用于判断一个数字是否为偶数。然后,我们使用 std::find_if 函数在 numbers 容器中查找第一个满足条件的偶数,并输出结果。

值得注意的是,std::find_if 在查找到满足条件的元素后,会立即停止搜索并返回该元素的迭代器。如果要查找出多个满足条件的元素,可以使用 std::find_if 结合其他算法函数或循环进行迭代查找。

三.内建函数对象

当涉及到内建函数对象时,可以根据它们的功能将它们分为三类: 算术函数对象、逻辑函数对象和关系函数对象。

  1. 算术函数对象:

    • std::plus: 加法操作。
    • std::minus: 减法操作。
    • std::multiplies: 乘法操作。
    • std::divides: 除法操作。
    • std::modulus: 取模操作。
  2. 逻辑函数对象:

    • std::logical_and: 逻辑与操作。
    • std::logical_or: 逻辑或操作。
    • std::logical_not: 逻辑非操作。
  3. 关系函数对象:

    • std::less: 小于比较。
    • std::less_equal: 小于等于比较。
    • std::greater: 大于比较。
    • std::greater_equal: 大于等于比较。
    • std::equal_to: 等于比较。
    • std::not_equal_to: 不等于比较。

这些函数对象可以通过重载 operator() 来执行特定的操作或比较,它们被设计为与标准库算法一起使用,以提供通用的功能。通过使用这些函数对象,我们可以以一种通用且灵活的方式处理算术、逻辑和关系操作。

当涉及到内建函数对象时,我们可以通过以下示例来展示它们的使用:

  1. 算术函数对象:
#include <iostream>
#include <functional>int main() {std::plus<int> add;int a = 5, b = 10;int result = add(a, b);std::cout << "Addition result: " << result << std::endl;  // 输出:15return 0;
}

在上述示例中,我们使用了 std::plus 函数对象来执行加法操作,将数字 ab 相加,并将结果存储在 result 变量中。

  1. 逻辑函数对象:
#include <iostream>
#include <functional>int main() {std::logical_and<bool> logicAnd;bool value1 = true, value2 = false;bool result = logicAnd(value1, value2);std::cout << "Logical AND result: " << std::boolalpha << result << std::endl;  // 输出:falsereturn 0;
}

在上述示例中,我们使用了 std::logical_and 函数对象来执行逻辑与操作,对 value1value2 进行逻辑与运算,并将结果存储在 result 变量中。

  1. 关系函数对象:
#include <iostream>
#include <functional>int main() {std::less<int> lessThan;int a = 5, b = 10;bool result = lessThan(a, b);std::cout << "Less than result: " << std::boolalpha << result << std::endl;  // 输出:truereturn 0;
}

在上述示例中,我们使用了 std::less 函数对象来执行小于比较,判断 a 是否小于 b,并将结果存储在 result 变量中。

这些示例演示了如何使用内建函数对象进行算术、逻辑和关系操作。您可以通过实例化适当的函数对象类模板,然后将其用作函数调用,以便执行所需的操作或比较。

请注意,这些示例可能只是演示了函数对象的一小部分用法,这些函数对象在标准库的算法和其他使用场景中非常有用。

好的,下面是一个整理成表格的例子,展示了内建函数对象及其用途的示例。

函数对象用途示例
std::plus加法操作std::plus()(2, 3) // 输出:5
std::minus减法操作std::minus()(5, 2) // 输出:3
std::multiplies乘法操作std::multiplies()(3, 4) // 输出:12
std::divides除法操作std::divides()(10, 2) // 输出:5
std::modulus取模操作std::modulus()(10, 3) // 输出:1
std::logical_and逻辑与操作std::logical_and()(true, false) // 输出:false
std::logical_or逻辑或操作std::logical_or()(true, false) // 输出:true
std::logical_not逻辑非操作std::logical_not()(true) // 输出:false
std::less小于比较std::less()(2, 5) // 输出:true
std::less_equal小于等于比较std::less_equal()(5, 5) // 输出:true
std::greater大于比较std::greater()(5, 2) // 输出:true
std::greater_equal大于等于比较std::greater_equal()(5, 5) // 输出:true
std::equal_to相等比较std::equal_to()(2, 2) // 输出:true
std::not_equal_to不等比较std::not_equal_to()(2, 5) // 输出:true

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI开发系列(二):大语言模型发展史及Transformer架构详解

全文共1.8w余字&#xff0c;预计阅读时间约60分钟 | 满满干货&#xff0c;建议收藏&#xff01; 一、介绍 在2020年秋季&#xff0c;GPT-3因其在社交媒体上病毒式的传播而引发了广泛关注。这款拥有超过1.75亿参数和每秒运行成本达到100万美元的大型语言模型&#xff08;Large …

MFC项目改为多字节字符集界面风格变为win98风格的问题

在项目->属性->配置属性中,将字符集改为多字节字符集&#xff0c;则界面风格变成了win98风格 解决办法&#xff0c;在stdafx.h中有 #ifdef _UNICODE #if defined _M_IX86 #pragma comment(linker,"/manifestdependency:\"typewin32 nameMicrosoft.Windows.Com…

Hbase API

hbase版本&#xff1a;2.3.5 1、创建maven工程&#xff0c;引入pom依赖 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency><dependency>…

61、SpringBoot -----跨域资源的设置----局部设置和全局设置

★ 跨域资源共享的意义 ▲ 在前后端分离的开发架构中&#xff0c;前端应用和后端应用往往是彻底隔离的&#xff0c;二者不在同一个应用服务器内、甚至不再同一台物理节点上。 因此前端应用和后端应用就不在同一个域里。▲ 在这种架构下&#xff0c;前端应用可能采用前端框架&a…

了解稀疏数组

稀疏数组&#xff08;一种数据结构&#xff09; package com.mypackage.array;public class Demo08 {public static void main(String[] args) {//1.创建一个二维数组 11*11// 0&#xff1a;没有棋子 1&#xff1a;黑棋 2&#xff1a;白棋int[][] array1 new int[11][11];…

Redis总结(一)

目录 Redis简介 为什么使用Redis作为MySQL的缓存&#xff1f; 高性能 高并发 Redis数据结构及其使用场景分别是什么&#xff1f; String&#xff08;字符串&#xff09; 内部实现 常用命令 普通字符串基本操作 批量设置 计数器&#xff08;字符串内容为整数时使用&a…

学习网络编程No.6【将服务器日志和守护进程化】

引言&#xff1a; 北京时间&#xff1a;2023/9/1/21:15&#xff0c;下午刚更新完博客&#xff0c;同理再接再厉&#xff0c;这样整天不需要干什么&#xff0c;除了玩手机的日子不多了&#xff0c;马上就要开学&#xff0c;每天需要签到签退的日子就要来临&#xff0c;烦躁&…

每日刷题-5

目录 一、选择题 二、算法题 1、不要二 2、把字符串转换成整数 一、选择题 1、 解析&#xff1a;printf(格式化串&#xff0c;参数1&#xff0c;参数2,.….)&#xff0c;格式化串: printf第一个参数之后的参数要按照什么格式打印&#xff0c;比如%d--->按照整形方式打印&am…

基于人体呼出气体的电子鼻系统的设计与实现

基于人体呼出气体的电子鼻系统的设计与实现 摘要 电子鼻技术是通过模式识别技术对传感器采集的人体呼出气体进行分类训练的方法。本文研究实现的电子鼻系统包括下面几个部分:首先搭建以Arduino为控制核心的气路采集装置&#xff0c;包括MOS传感器和双阀储气袋构建的传感器阵列和…

【python绘图—colorbar操作学习】

文章目录 Colorbar的作用Colorbar的操作截取cmap拼接cmap双刻度列colorbar 引用 Colorbar的作用 Colorbar&#xff08;颜色条&#xff09;在绘图中的作用非常重要&#xff0c;它主要用于以下几个方面&#xff1a; 表示数据范围&#xff1a; Colorbar可以显示图中的颜色映射范围…

使用内网端口映射方案,轻松实现U8用友ERP的本地部署异地远程访问——“cpolar内网穿透”

文章目录 前言1. 服务器本机安装U8并调试设置2. 用友U8借助cpolar实现企业远程办公2.1 在被控端电脑上&#xff0c;点击开始菜单栏&#xff0c;打开设置——系统2.2 找到远程桌面2.3 启用远程桌面 3. 安装cpolar内网穿透3.1 注册cpolar账号3.2 下载cpolar客户端 4. 获取远程桌面…

对抗生成网络总结

对一些基本的对抗生成网络的总结。部分内容整理自Teeyohuang’s blog 文章目录 GAN (NeurIPS, 2014)CGANDCGANStackGANPix2Pix (CVPR, 2017)CycleGAN (ICCV, 2017)SRGAN (CVPR, 2017)StyleGAN (CVPR, 2019) GAN (NeurIPS, 2014) Generative adversarial nets m i n G m a x D …