C++STL函数对象的应用

STL函数对象

文章目录

      • STL函数对象
        • 1.基本概念
        • 2.使用方法
          • 1. 简单函数对象示例
          • 2. 函数对象作为算法参数
          • 3. Lambda表达式作为函数对象
        • 2.一元谓词和二元谓词
          • 1.一元谓词
          • 2.二元谓词
          • 3.总结
        • 3.算术仿函数
          • 1.使用示例
          • 2.Lambda表达式的替代
        • 4.关系仿函数
        • 5.逻辑仿函数

C++中的函数对象(Function Object),也常被称为仿函数(Functor),是一种模拟函数行为的类对象。它们允许用户自定义操作,并能像普通函数那样被调用,同时还能携带状态,这是普通函数所不具备的能力。函数对象是实现泛型编程、算法定制等高级技术的关键组件之一。下面概述了函数对象的基本概念和使用方法:

1.基本概念
  1. 类定义:函数对象通常是一个重载了()操作符的类。这个操作符使得该类的对象可以像函数一样被调用。
  2. 状态携带:与普通函数不同,函数对象可以拥有成员变量,从而在不同的调用之间保持状态。
  3. 类型要求:为了能够用于标准库算法中,函数对象需要满足可调用对象的要求,即至少要有一个operator()成员函数。
2.使用方法
1. 简单函数对象示例
#include <iostream>

// 定义一个简单的函数对象类,重载了()操作符
class Adder {
public:
    // 构造函数可以初始化内部状态
    Adder(int add_value) : value(add_value) {}

    // 重载()操作符,使得对象可以像函数一样被调用
    int operator()(int x) {
        return x + value;
    }

private:
    int value; // 成员变量,保存加到输入值上的额外值
};

int main() {
    Adder addFive(5); // 创建一个Adder对象,初始化加值为5
    std::cout << addFive(10) << std::endl; // 调用仿函数,输出15
    return 0;
}
2. 函数对象作为算法参数

C++标准库中的许多算法都接受函数对象作为参数,以定制其行为。例如,std::sort可以通过传递自定义比较函数来改变排序规则。

#include <algorithm>
#include <vector>
#include <iostream>

// 一个用于降序比较的仿函数
struct DescComp {
    bool operator()(int a, int b) {
        return a > b;
    }
};

int main() {
    std::vector<int> vec = {1, 3, 5, 2, 4};
    
    // 使用自定义的降序比较仿函数进行排序
    std::sort(vec.begin(), vec.end(), DescComp());
    
    for(int i : vec) {
        std::cout << i << " ";
    }
    // 输出:5 4 3 2 1
    return 0;
}
3. Lambda表达式作为函数对象

从C++11开始,Lambda表达式提供了一种更简洁的方式创建匿名函数对象,它可以直接在代码中定义并使用。

#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // 使用Lambda表达式作为自定义排序规则
    std::sort(vec.begin(), vec.end(), [](int a, int b) {
        return a > b; // 降序排列
    });
    
    for(int i : vec) {
        std::cout << i << " ";
    }
    // 输出:5 4 3 2 1
    return 0;
}

通过上述示例,可以看到函数对象在C++中提供了强大的灵活性和定制能力,是泛型编程和算法设计中的重要工具。

2.一元谓词和二元谓词

C++中的一元谓词和二元谓词是两种特定类型的函数对象,它们在标准模板库(STL)的算法中扮演着重要的角色,用于定制算法的行为。以下是它们的基本概念和使用方法:

1.一元谓词

基本概念:

  • 一元谓词是只接受一个参数的函数对象,并返回一个布尔值(bool)。
  • 这个函数对象通常用来测试或判断传入的参数是否满足某个条件。
  • 在STL算法中,一元谓词常用于从容器中选择满足特定条件的元素,例如std::find_if

使用示例:

#include <algorithm>
#include <vector>
#include <iostream>

// 一元谓词函数对象,检查一个数是否为偶数
struct IsEven {
    bool operator()(int x) {
        return x % 2 == 0;
    }
};

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
    auto it = std::find_if(numbers.begin(), numbers.end(), IsEven());
    
    if(it != numbers.end())
        std::cout << "The first even number is: " << *it << std::endl;
    else
        std::cout << "No even number found." << std::endl;
    
    return 0;
}
2.二元谓词

基本概念:

  • 二元谓词接受两个参数,并返回一个布尔值。
  • 它们通常用于比较这两个参数是否满足某种关系,如小于、大于、等于等。
  • 在STL中,二元谓词广泛应用于排序算法(如std::sort)、查找算法(如std::binary_search)等,用以定义元素间的比较规则。

使用示例:

#include <algorithm>
#include <vector>
#include <iostream>

// 二元谓词函数对象,检查第一个数是否大于第二个数
struct GreaterThan {
    bool operator()(int a, int b) {
        return a > b;
    }
};

int main() {
    std::vector<int> values = {5, 2, 9, 1, 5, 6};
    
    // 使用二元谓词进行降序排序
    std::sort(values.begin(), values.end(), GreaterThan());
    
    for(int val : values) {
        std::cout << val << " ";
    }
    // 输出:9 6 5 5 2 1
    
    return 0;
}
3.总结

无论是哪种谓词,它们的核心作用都是提供一个逻辑判断,使得STL算法能够基于这些逻辑判断来处理数据。一元谓词适用于单个元素的条件筛选,而二元谓词则用于定义元素间的关系,比如排序或查找时的比较逻辑。随着C++11及之后版本对Lambda表达式的支持,直接在算法中内联定义谓词变得更加方便快捷。

3.算术仿函数

C++ STL(标准模板库)提供了一系列算术仿函数(Arithmetic Functors),它们是对基本数学运算的封装,使得这些运算可以像函数对象一样被使用,尤其是在算法中进行定制操作时非常有用。以下是一些常用的算术仿函数及其简单说明:

  1. plus:定义了加法操作,重载了operator()以执行加法。
  2. minus:定义了减法操作。
  3. multiplies:实现了乘法操作。
  4. divides:提供了除法操作。
  5. modulus:用于取模运算。
  6. negate:执行取负操作。
1.使用示例

这些仿函数位于<functional>头文件。

#include <iostream>
#include <functional>
#include <algorithm> // 用于std::transform

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::vector<int> results;

    // 使用plus仿函数将每个元素自身相加(即每个元素乘以2)
    results.resize(numbers.size());
    std::transform(numbers.begin(), numbers.end(), results.begin(), std::plus<int>());

    // 输出结果
    for(int res : results) {
        std::cout << res << " ";
    }
    // 输出:2 4 6 8 10

    return 0;
}

在这个例子中,std::transform算法结合std::plus<int>()仿函数,将numbers容器中的每个元素与其自身相加,结果存储在results容器中。

2.Lambda表达式的替代

虽然算术仿函数非常有用,但在C++11及以后的版本中,Lambda表达式提供了更加灵活和直观的方式来定义这样的操作,特别是在复杂逻辑或需要访问外部变量时。然而,对于简单的数学运算,直接使用STL提供的算术仿函数可以简化代码,提高可读性。

4.关系仿函数

关系仿函数封装了基本的比较运算符,位于<functional>头文件中。

  1. equal_to:测试两个参数是否相等。
  2. not_equal_to:测试两个参数是否不相等。
  3. greater:测试第一个参数是否大于第二个参数。
  4. less:测试第一个参数是否小于第二个参数。
  5. greater_equal:测试第一个参数是否大于等于第二个参数。
  6. less_equal:测试第一个参数是否小于等于第二个参数。
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    int target = 3;
    

    // 使用equal_to查找目标值
    if(std::find_if(vec.begin(), vec.end(), std::bind2nd(std::equal_to<int>(), target)) != vec.end()) {
        std::cout << target << " is found in the vector." << std::endl;
    } else {
        std::cout << target << " is not found in the vector." << std::endl;
    }
    return 0;

}
5.逻辑仿函数

逻辑仿函数用于组合或反转布尔值,它们也是在<functional>中定义的,包括:

  1. logical_and:对两个布尔值执行逻辑与操作。
  2. logical_or:对两个布尔值执行逻辑或操作。
  3. logical_not:对一个布尔值执行逻辑非操作。

逻辑仿函数示例

#include <iostream>
#include <functional>

int main() {
    bool flag1 = true, flag2 = false;
    
    // 使用逻辑与
    if(std::logical_and<bool>()(flag1, flag2)) {
        std::cout << "Both flags are true." << std::endl;
    } else {
        std::cout << "Not both flags are true." << std::endl;
    }
    
    // 使用逻辑或
    if(std::logical_or<bool>()(flag1, flag2)) {
        std::cout << "At least one flag is true." << std::endl;
    }
    
    // 使用逻辑非
    std::cout << "Negation of flag2: " << std::logical_not<bool>()(flag2) << std::endl;
    
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【EFK】efk 8收集docker容器日志测试

前言 目前&#xff0c;efk 全家桶已经更新到版本8 了&#xff0c;本章节我们使用8版本的elk搭建日志收集系统&#xff0c;了解它的配置运行过程&#xff0c;方便以后在更复杂的环境中更好的使用。 版本默认就是8最新的&#xff0c;也可以自己指定其他8的版本 elasticsearch: …

DisFormer:提高视觉动态预测的准确性和泛化能力

最新的研究进展已经显示出目标中心的表示方法在视觉动态预测任务中可以显著提升预测精度&#xff0c;并且增加模型的可解释性。这种表示方法通过将视觉场景分解为独立的对象&#xff0c;有助于模型更好地理解和预测场景中的变化。 尽管在静态图像的解耦表示学习方面已经取得了一…

【刷题汇总--游游的you、腐烂的苹果、孩子们的游戏(圆圈中最后剩下的数)】

C日常刷题积累 今日刷题汇总 - day0051、游游的you1.1、题目1.2、思路1.3、程序实现 - 蛮力法1.4、程序实现 - 贪心(优化) 2、腐烂的苹果2.1、题目2.2、思路2.3、程序实现 - bfs 3、孩子们的游戏(圆圈中最后剩下的数)3.1、题目3.2、思路3.3、程序实现 -- 环形链表3.4、程序实现…

html+js+css在线倒计时

代码在图片后面 点赞加关注 谢谢大佬照顾&#x1f61c; 图例 时间到前 时间到后 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width,…

分支与循环

目录 1. if语句 1&#xff09;if 2) else 3&#xff09;分支中包含多条语句 4&#xff09;if嵌套 2.关系操作符 3.条件操作符 4.逻辑操作符&#xff1a;&& || ! 1) 逻辑取反运算符 !​编辑 2 与运算符​编辑 3) 或运算符​编辑 4) 闰年的判断 5) 短路 …

如何使用 SwiftUI 构建 visionOS 应用

文章目录 前言WindowsVolumes沉浸式空间结论 前言 Apple Vision Pro 即将推出&#xff0c;现在是看看 SwiftUI API 的完美时机&#xff0c;这使我们能够将我们的应用程序适应 visionOS 提供的沉浸式世界。苹果表示&#xff0c;构建应用程序的最佳方式是使用 Swift 和 SwiftUI。…

鸿蒙本地签名不匹配问题

连接鸿蒙手机运行项目报如下错误 这是由于本地签名和鸿蒙设备签名不匹配导致的&#xff0c;需要注释掉如下代码&#xff0c;选择file project 自动签名 勾选auto选项&#xff0c;会在build-profile.json5中生成一个签名&#xff0c;然后运行就ok了~

NXP i.MX8系列平台开发讲解 - 3.18 Linux tty子系统介绍(一)

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 目录 1. TTY 起源 2. Linux 系统中的TTY 2.1 Linux TTY 设备形式 2.2 Linux TTY framework 2.3 驱动核心相关文件…

「植物大战僵尸杂交版」保姆级攻略大全以及下载指南

植物大战僵尸杂交版自推出以来&#xff0c;以其独特的植物组合和策略玩法&#xff0c;迅速赢得了玩家们的喜爱。如果你正准备加入这场植物与僵尸的战斗&#xff0c;或者已经在战斗中寻求突破&#xff0c;那么这份保姆级的攻略大全将是你的得力助手。同时&#xff0c;我们也提供…

PLL和CDR的内部结构及其区别

比较PLL和CDR的内部结构及其区别&#xff1a; 基本结构&#xff1a; PLL&#xff08;相位锁定环&#xff09;&#xff1a; 相位检测器环路滤波器压控振荡器&#xff08;VCO&#xff09;分频器&#xff08;可选&#xff0c;用于频率合成&#xff09; CDR&#xff08;时钟数据恢复…

complex复数库学习

此头文件是数值库的一部分。本篇介绍complex的基本用法。 常用的API如下&#xff1a; 运算 real 返回实部 (函数模板) imag 返回虚部 (函数模板) abs(std::complex) 返回复数的模 (函数模板) arg 返回辐角 (函数模板) norm 返回模(范数)的平方 (函数模板) conj 返回复共轭 (函…

GuLi商城-商品服务-API-品牌管理-效果优化与快速显示开关

<template><div class"mod-config"><el-form :inline"true" :model"dataForm" keyup.enter.native"getDataList()"><el-form-item><el-input v-model"dataForm.key" placeholder"参数名&qu…

首个“可控”人物视频生成大模型--商汤Vimi:一张照片生成一分钟视频

商汤科技又整大活了&#xff0c;只需一张照片就能生成一分钟视频&#xff01; 7月4日&#xff0c;商汤发布了业内首个面向C端用户的、“可控”人物视频生成大模型产品Vimi&#xff0c;毫不夸张的说&#xff0c;视频制作者的福音来了&#xff01; Vimi有什么特别之处&#xff1…

Python爬虫零基础实战,简洁实用!

1.爬虫简介 简单来讲&#xff0c;爬虫就是一个探测机器&#xff0c;它的基本操作就是模拟人的行为去各个网站溜达&#xff0c;点点按钮&#xff0c;查查数据&#xff0c;或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。 你可以简单地想象&#xff1a;每个…

Ubuntu 22.04 安装中文字体

笔者在用OpenCV4.9处理图片加水印时&#xff0c;中文乱码。原来是Ubuntu 22.04发行版缺少中文字体支持&#xff0c;因此&#xff0c;笔者就找资料安装了需要的中文字体&#xff0c;特此记录&#xff0c;以备后查。 1、打开终端&#xff1a; 2、更新软件包列表&#xff1a; su…

哏号分治,CF103D - Time to Raid Cowavans

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 103D - Time to Raid Cowavans 二、解题报告 1、思路分析 想了半天数据结构最终选择根号分治 我们考虑 大于 550 的公差直接暴力 小于550 的公差的所有询问&#xff0c;我们直接计算该公差后缀和&#xf…

【Linux进阶】磁盘分区3——目录树,挂载

Linux安装模式下&#xff0c;磁盘分区的选择&#xff08;极重要&#xff09; 在Windows 系统重新安装之前&#xff0c;你可能会事先考虑&#xff0c;到底系统盘C盘要有多大容量&#xff1f;而数据盘D盘又要给多大容量等&#xff0c;然后实际安装的时候&#xff0c;你会发现其实…

Rocky Linux 9.4基于官方源码制作openssh 9.8p1二进制rpm包 —— 筑梦之路

2024年7月1日&#xff0c;openssh 9.8版本发布&#xff0c;主要修复了CVE-2024-6387安全漏洞。 由于centos 7的生命周期在6月30日终止&#xff0c;因此需要逐步替换到Rocky Linux&#xff0c;后续会有更多分享关于Rocky Linux的文章。 环境说明 1. 操作系统版本 cat /etc/o…

【Odoo开源ERP】别把ERP与进销存软件混为一谈

导读&#xff1a;企业使用ERP软件能够实现管理升级&#xff0c;多方信息集成&#xff0c;按照既定策略逻辑运算&#xff0c;生成计划建议&#xff0c;减少人力成本&#xff0c;提高准确率的同时提高经营能力。 ERP&#xff0c;是MRP II的下一代软件&#xff0c;除了MRP II已有的…