C++:函数符(一)

正文

函数对象也叫函数符,函数符是可以以函数方式与()结合使用的任意对象。这包括函数名指向函数的指针重载了()运算符的类对象。

上面这句话的意思是指:函数名、指向函数的指针和重载了括号运算符的类对象与括号结合,从而以函数方式实现某种功能。
对于 for_each(),第三个参数我们一般可以写一个函数名,或者类的对象(该类必须对括号运算符进行了重载),但是不可以为一个函数指针,因为函数指针的类型已经确定,要迭代的对象类型并不会提前知道。比如:

#include <iostream>
#include <vector>
#include <algorithm>// 定义一个类,其中重载了 () 运算符
class FunctionObject {
public:// 重载 () 运算符,用于执行特定操作void operator()(int num) const {std::cout << num << " squared is: " << num * num << std::endl;}
};int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用函数对象执行特定操作,这里是输出数字的平方FunctionObject f;std::for_each(numbers.begin(), numbers.end(), f);return 0;
}

当然,上面的代码还可以改成本:

...int main() {
..std::for_each(numbers.begin(), numbers.end(), FunctionObject());
...
}

这是类 FunctionObject 的构造函数构造的一个匿名对象。如果我们用函数指针:


```cpp
#include <iostream>
#include <vector>
#include <algorithm>// 定义一个函数,用于执行特定操作
void squareAndPrint(int num) {std::cout << num << " squared is: " << num * num << std::endl;
}int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用函数指针执行特定操作,这里是输出数字的平方void (*funcPtr)(double) = squareAndPrint;std::for_each(numbers.begin(), numbers.end(), funcPtr); // 编译错误return 0;
}

再来看看 for_each() 源码:

// for_eachtemplate <class _InputIterator, class _Function>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
_Function
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
{for (; __first != __last; ++__first)__f(*__first);return __f;
}

可以看到,只要第三个参数能结合括号运算符,并且接受的参数 *__first类型正确,就能编译通过,事实上也确实如此。

g++ func_ptr.cxx -o main -std=c++11
func_ptr.cxx:14:12: error: cannot initialize a variable of type 'void (*)(double)' with an lvalue of type 'void (int)': type mismatch at 1st parameter ('double' vs 'int')void (*funcPtr)(double) = squareAndPrint;^                  ~~~~~~~~~~~~~~
1 error generated.

我们修改代码:

...
int main() {
...void (*funcPtr)(int) = squareAndPrint;std::for_each(numbers.begin(), numbers.end(), funcPtr); // 编译正确
...
}

运行结果:

g++ func_ptr.cxx -o main -std=c++11
~/Cpp_Notes/chap16/func ./main
1 squared is: 1
2 squared is: 4
3 squared is: 9
4 squared is: 16
5 squared is: 25

你可能会问,为什么?第三个参数明明去要一个对象,我们传入了一个函数指针却能编译通过,难道计算机科学不存在了?

这是因为 C++ 允许将函数指针隐式转换为函数对象。在这种情况下,编译器将自动创建一个临时的函数对象来包装函数指针,并将其传递给 std::for_each 函数。

因此,虽然 std::for_each(numbers.begin(), numbers.end(), funcPtr); 看起来似乎是将一个函数指针传递给 for_each 函数,但实际上编译器会将其转换为类似于 std::for_each(numbers.begin(), numbers.end(), FuncWrapper(funcPtr)); 的形式,其中 FuncWrapper 是一个临时的函数对象,用于包装函数指针 funcPtr

使用函数指针作为算法的操作函数参数是合法的,但不建议使用函数指针的主要原因有以下几点:

  1. 可读性和可维护性差:函数指针的语法相对复杂,不够直观,可能会降低代码的可读性和可维护性。相比之下,使用函数对象或 lambda 表达式更加直观和易于理解。

  2. 灵活性不足:函数指针只能指向静态函数或全局函数,无法捕获外部变量。而函数对象或 lambda 表达式可以轻松捕获外部变量,提供更大的灵活性。

  3. 类型安全性:函数指针在类型匹配上需要开发者自行确保,容易出现类型不匹配的问题。而函数对象或 lambda 表达式在编译时会进行类型检查,更加安全。

  4. 性能问题:函数指针的调用可能会引入额外的开销,因为在调用函数指针时需要进行间接跳转。而函数对象或 lambda 表达式可能更加高效。

相比之下,我们可以使用函数对象或者 lambda 表达式作为 std::for_each 的第三个参数,因为它们都是可调用对象。函数对象是一个类,重载了 operator() 运算符,可以像函数一样被调用。Lambda 表达式也是一个可调用对象,可以在需要时直接定义并使用。

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

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

相关文章

【行为型模式】解释器模式

一、解释器模式概述 解释器模式定义&#xff1a;给分析对象定义一个语言&#xff0c;并定义该语言的文法表示&#xff0c;再设计一个解析器来解释语言中的句子。也就是说&#xff0c;用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口&#xff0c;该接口…

python高级进阶

目录 一、str字符串 1. 字符串定义 2. 获取字符串中元素 3. 遍历字符串 4. 字符串常见操作 二、set集合 1. 集合的创建 2. 遍历集合中的元素 3. 集合中添加元素 4. 集合删除元素 三、字典 1. 字典的定义 2. 字典的特点 3. 字典增删改查 4. 字典遍历 四、slice切片…

【经验总结】Ubuntu 源代码方式安装 Microsoft DeepSpeed

1. 背景介绍 使用 DeepSpeed 在多服务器上分布式训练大模型 2. 安装方法 2.1 查看显卡参数 ~$ CUDA_VISIBLE_DEVICES0 python -c "import torch; print(torch.cuda.get_device_capability())" (8, 0) ~$ CUDA_VISIBLE_DEVICES0 python -c "import torch; pr…

python常见语法

变量赋值&#xff1a; my_var 10 基本数据类型&#xff1a; 整数&#xff08;int&#xff09;、浮点数&#xff08;float&#xff09;、字符串&#xff08;str&#xff09;、布尔值&#xff08;bool&#xff09;、列表&#xff08;list&#xff09;、元组&#xff08;tuple&…

代码随想录第三十天|无重叠区间| 划分字母区间| 合并区间

今天三道都是重叠区间问题&#xff0c;重叠区间问题第一步就是先对数组进行排序&#xff0c;才能进行后续操作。 无重叠区间 这一题和昨天的最少多少支箭射爆气球的解法是相同的&#xff0c;判断相邻区间是否重叠&#xff0c;若两个区间重叠了则找出重叠区间最小右边界&#…

怎样用PHP语言实现远程控制三路开关

怎样用PHP语言实现远程控制三路开关呢&#xff1f; 本文描述了使用PHP语言调用HTTP接口&#xff0c;实现控制三路开关&#xff0c;三路开关可控制三路照明、排风扇等电器。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称厂商1智能WiFi墙…

C++:模板(初级)

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;模板&#xff08;初级&#xff09;》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞…

Docker容器搭建Hadoop集群(hadoop-3.1.3)

Docker容器环境下搭建Hadoop集群&#xff08;完全分布式&#xff09; hadoop版本为hadoop-3.1.3 &#xff08;1&#xff09;安装额外的速度较快的镜像库 yum install -y epel-release &#xff08;2&#xff09;安装同步工具&#xff0c;方便在多台服务器上进行文件的传输 …

Oracle Hint 语法详解

什么是Hint Hint 是 Oracle 提供的一种 SQL 语法&#xff0c;它允许用户在 SQL 语句中插入相关的语法&#xff0c;从而影响 SQL 的执行方式。 因为 Hint 的特殊作用&#xff0c;所以对于开发人员不应该在代码中使用它&#xff0c;Hint 更像是 Oracle 提供给 DBA 用来分析诊断问…

从零学算法377

377. 组合总和 Ⅳ 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3], target 4 输出&#xff…

【操作系统】进程同步(水果盘问题)使用Python多线程threading实现

一、进程同步&#xff08;水果盘问题&#xff09; 1、吃水果问题&#xff1a;桌子有一只盘子&#xff0c;只允许放一个水果&#xff0c;父亲专向盘子放苹果&#xff0c;母亲专向盘子放桔子 儿子专等吃盘子的桔子&#xff0c;女儿专等吃盘子的苹果。只要盘子为空&#xff0c;父…

QA测试开发工程师面试题满分问答20: 软件的安全性应从哪几个方面去测试?

软件的安全性测试应从多个方面进行&#xff0c;并确保覆盖以下关键方面&#xff1a; 当回答问题时&#xff0c;可以根据自己的经验和知识&#xff0c;从上述要点中选择适合的方面进行详细说明。强调测试的综合性、全面性和持续性&#xff0c;并强调测试的重要性以及如何与开发团…

IDEA最好用插件推荐

1 背景 俗话说&#xff1a;“工欲善其事必先利其器”&#xff0c;本问介绍几款强大实用的 IDEA 插件&#xff0c;助力大家开发。 希望大家做一个聪明又努力的人&#xff0c;而不只是一个努力的人。 以下插件大都可以通过 IDEA 自带的插件管理中心安装&#xff0c;如果搜不到可以…

python字典和集合

字典&#xff08;Dictionary&#xff09; 键值对&#xff1a;字典存储键值对&#xff08;key-value pairs&#xff09;&#xff0c;其中键&#xff08;key&#xff09;是唯一的&#xff0c;而值&#xff08;value&#xff09;可以是任何数据类型。可变&#xff1a;字典是可变的…

恶补《操作系统》2_1——王道学习笔记

2操作系统-进程 2.1_1 进程的定义、组成、组织方式、特征 组成&#xff1a;PCB&#xff08;进程存在唯一的标志&#xff09;&#xff0c;程序段&#xff0c;数据段 组织方式&#xff1a;链接方式&#xff0c;指针指向不同的队列&#xff1b;索引方式&#xff0c;索引表 特征…

Uptime Kuma 使用指南:一款简单易用的站点监控工具

我平时的工作会涉及到监控&#xff0c;而站点是一个很重要的监控项。项目上线后&#xff0c;我们通常会将站点监控配置到云平台上&#xff0c;以检测各站点的连通性。但随着项目不断增多&#xff0c;云平台上的配额就有点捉急了。针对这个情况&#xff0c;我们可以试试这个开源…

使用H5+app在安卓5.1离线环境实现文字转语音

在Vue中实现中文文字转语音的方法可以使用HTML5的SpeechSynthesis API,同时需要考虑到在H5+ App里面的离线环境。 在配置文件中正确引入plus库: <script src="http://www.dcloud.io/helloh5plus/api.js"></script> 在Vue组件中使用SpeechSynthesi…

设计模式——状态模式19

状态模式是一种行为设计模式&#xff0c; 允许一个对象在其内部状态改变时改变它的行为&#xff0c;对象看起来好像修改了它的类。状态模式的核心是状态与行为绑定&#xff0c;不同的状态对应不同的行为。 设计模式&#xff0c;一定要敲代码理解 状态行为抽象 //在某种状态下&…

【网安小白成长之路】9.sql注入操作

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f51e; 《网安小白成长之路(我要变成大佬&#x1f60e;&#xff01;&#xff01;)》真实小白学习历程&#xff0c;手把手带你一起从入门到入狱&#x1f6ad; &…

SpringBoot整合七牛云实现图片的上传管理

唠嗑部分 各位小伙伴大家好&#xff0c;我是全栈小白&#xff0c;今天我们来分享一下SpringBoot如何整合七牛云存储实现图片的上传与存储 首先我们来说说图片存储&#xff0c;在项目中图片几乎是必不可少的&#xff0c;那么大家会选择怎样存储呢&#xff0c;当然有几种方案 …