0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

引入仿函数(functor)原因

Q4MP_gh_c472c21 来源:dnbc66 作者:dnbc66 2020-11-16 16:49 次阅读

【导读】:在我们日常编码中会发现有些功能代码,会不断的在不同的成员函数中用到,但是又不好将这些代码独立成一个成员函数。解决办法之一就是写一个公共的函数,不过函数用到的一些变量,就可能会成为全局变量。再说为了复用这么一段代码,就要单立出一个函数,也不是很好维护。此时就可以用到仿函数了。

以下是正文

引入仿函数(functor)原因

先考虑一个简单的例子:假设有一个vector,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码可能长成这样:

bool LengthIsLessThanFive(const string& str){returnstr.length()< 5;    }int res=count_if(vec.begin(), vec.end(), LengthIsLessThanFive);

其中count_if函数的第三个参数是一个函数指针,返回一个bool类型的值。一般的,如果需要将特定的阈值长度也传入的话,我们可能将函数写成这样:

bool LenthIsLessThan(const string& str, int len) {returnstr.length()< len;}

这个函数看起来比前面一个版本更具有一般性,但是他不能满足count_if函数的参数要求:count_if要求的是unary function(仅带有一个参数)作为它的最后一个参数。所以问题来了,怎么样找到以上两个函数的一个折中的解决方案呢?

这个问题其实可以归结于一个data flow的问题,要设计这样一个函数,使其能够access这个特定的length值,回顾我们已有的知识,有三种解决方案可以考虑:

(1)函数的局部变量:

局部变量不能在函数调用中传递,而且caller无法访问。

(2)函数的参数:

这种方法我们已经讨论过了,多个参数不适用于count_if函数。

(3)全局变量:

我们可以将长度阈值设置成一个全局变量,代码可能像这样:

int maxLength;bool LengthIsLessThan(const string& str) { return str.length() < maxLength;}int res=count_if(vec.begiin(), vec.end(), LengthIsLessThan);

这段代码看似很不错,实则不符合规范,更重要的是,它不优雅。原因有以下几点要考虑:

(1)容易出错:

为什么这么说呢,我们必须先初始化maxLength的值,才能继续接下来的工作,如果我们忘了,则可能无法得到正确答案。此外,变量maxLength和函数LengthIsLessThan之间是没有必然联系的,编译器无法确定在调用该函数前是否将变量初始化,给码农平添负担。

(2)没有可扩展性:

如果我们每遇到一个类似的问题就新建一个全局变量,尤其是多人合作写代码时,很容易引起命名空间污染(namespace polution)的问题;当范围域内有多个变量时,我们用到的可能不是我们想要的那个。

(3)全局变量的问题:

每当新建一个全局变量,即使是为了coding的便利,我们也要知道我们应该尽可能的少使用全局变量,因为它的cost很高;而且可能暗示你这里有一些待解决的优化方案。

仿函数(functor)介绍

说了这么多,还是要回到我们原始的那个问题,有什么解决方案呢?答案当然就是这篇blog的正题部分:仿函数。

我们的初衷是想设计一个unary function,使其能做binary function的工作,这看起来并不容易,但是仿函数能解决这个问题。

先来看仿函数的通俗定义:仿函数(functor)又称为函数对象(function object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符,举个例子:

class Func{ public: void operator() (const string& str) const { cout<

>>>helloworld!

仿函数其实是上述解决方案中的第四种方案:成员变量。成员函数可以很自然的访问成员变量:

class StringAppend{ public: explicit StringAppend(const string& str) : ss(str){} void operator() (const string& str) const{ cout<

>>>hellois world

我相信这个例子能让你体会到一点点仿函数的作用了;它既能像普通函数一样传入给定数量的参数,还能存储或者处理更多我们需要的有用信息

让我们回到count_if的问题中去,是不是觉得问题变得豁然开朗了?

class ShorterThan { public: explicit ShorterThan(int maxLength) : length(maxLength) {} bool operator() (const string& str) const { return str.length() < length; } private: const int length;};//直接调用即可count_if(myVector.begin(), myVector.end(), ShorterThan(length));

这里需要注意的是,不要纠结于语法问题:ShorterThan(length)似乎并没有调用operator()函数?其实它调用了,创建了一个临时对象。你也可以自己加一些输出语句看一看。

这篇博文就先记到这里了,仿函数也在STL中大量涉及到,不彻底弄懂仿函数的问题看到STL源码就会一头包。后续可能再分享一些关于functor的资料和个人学习心得。

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    4326

    浏览量

    62560
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73610
  • 代码
    +关注

    关注

    30

    文章

    4776

    浏览量

    68509

原文标题:C++仿函数你会吗?

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    SUMIF函数与SUMIFS函数的区别

    SUMIF函数和SUMIFS函数都是Excel中用于条件求和的函数,它们可以帮助用户根据特定的条件对数据进行求和。尽管它们的基本功能相似,但在使用场景和功能上存在一些差异。以下是对这两个函数
    的头像 发表于 10-30 09:51 994次阅读

    OPA615峰值保持电路仿真仿不出来是怎么回事?

    求助~仿了好几天了,就是仿真不出来,输出上升到峰值后,马上下降了
    发表于 08-30 08:12

    神经元模型激活函数通常有哪几类

    神经元模型激活函数是神经网络中的关键组成部分,它们负责在神经元之间引入非线性,使得神经网络能够学习和模拟复杂的函数映射。以下是对神经元模型激活函数的介绍: 一、Sigmoid
    的头像 发表于 07-11 11:33 1015次阅读

    在HTTP的demo里面,回调函数不执行的原因

    在HTTP的demo里面,我用下面这个函数注册了一个回调函数,但是发现有时候正常执行有时候不执行,只是偶尔不执行,大部分时间是正常的。有没有人能提供一下原因可能的方向,谢谢!! espconn_regist_write_fin
    发表于 07-10 08:23

    BP神经网络激活函数怎么选择

    中,激活函数起着至关重要的作用,它决定了神经元的输出方式,进而影响整个网络的性能。 一、激活函数的作用 激活函数是BP神经网络中神经元的核心组成部分,其主要作用如下: 引入非线性:激活
    的头像 发表于 07-03 10:02 671次阅读

    卷积神经网络激活函数的作用

    起着至关重要的作用,它们可以增加网络的非线性,提高网络的表达能力,使网络能够学习到更加复杂的特征。本文将详细介绍卷积神经网络中激活函数的作用、常见激活函数及其特点,以及激活函数在网络优化中的应用。 一、激活
    的头像 发表于 07-03 09:18 861次阅读

    神经网络中的激活函数有哪些

    在神经网络中,激活函数是一个至关重要的组成部分,它决定了神经元对于输入信号的反应方式,为神经网络引入了非线性因素,使得网络能够学习和处理复杂的模式。本文将详细介绍神经网络中常用的激活函数,包括其定义、特点、数学形式以及在神经网络
    的头像 发表于 07-01 11:52 567次阅读

    如何在idf工程中引入mdf WiFi-Mesh函数

    我原先在idf下开发好的程序,如何引入mdf进行开发?需要用到WiFi-Mesh,看了下mdf下的例程是比较合适的,而idf下的wifi-mesh例程很粗略,想把mdf中的例程移植到我原来的idf工程里面去
    发表于 06-28 14:59

    函数发生器的常见故障及解决方法

    函数发生器,作为电子测试和测量领域的重要工具,其稳定性和可靠性对于实验和测试结果的准确性至关重要。然而,由于各种原因函数发生器在使用过程中可能会遇到各种故障。本文将详细介绍函数发生器
    的头像 发表于 05-15 11:45 983次阅读

    函数信号发生器的常见故障及原因分析

    的应用价值。然而,随着使用时间的增长,函数信号发生器可能会出现各种故障,影响其正常工作。本文将对函数信号发生器进行详细介绍,并分析其常见故障及原因
    的头像 发表于 05-10 16:13 1397次阅读

    stm32中FREERTOS的延时函数osDelayUntil()死机的原因

    我在使用STM32F4跑freertos的时候发现一旦使用osDelayUntil()函数,就会死机,但是用osDelay()函数就不会,按理说不是都可以用的吗?有知道原因的吗,谢谢!
    发表于 03-22 07:56

    回调函数(callback)是什么?回调函数的实现方法

    回调函数是一种特殊的函数,它作为参数传递给另一个函数,并在被调用函数执行完毕后被调用。回调函数通常用于事件处理、异步编程和处理各种操作系统和
    发表于 03-12 11:46 2890次阅读

    函数指针与回调函数的应用实例

    通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数函数指针可以像一般函数一样,用于调用函数、传递参数。
    的头像 发表于 03-07 11:13 399次阅读
    <b class='flag-5'>函数</b>指针与回调<b class='flag-5'>函数</b>的应用实例

    内联函数定义 为什么需要内联函数

    inline关键字是C99标准的型关键字,其作用是将函数展开,把函数的代码复制到每一个调用处。
    的头像 发表于 02-19 12:20 538次阅读

    函数指针和指针函数是不是一个东西?

    函数指针的本质是指针,就跟整型指针、字符指针一样,函数指针指向的是一个函数
    的头像 发表于 01-03 16:35 523次阅读
    <b class='flag-5'>函数</b>指针和指针<b class='flag-5'>函数</b>是不是一个东西?