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

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

3天内不再提示

关于C++仿函数

工程师 来源:dnbc66 作者:dnbc66 2020-10-23 15:28 次阅读

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

以下是正文

引入仿函数(functor)原因

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

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

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

bool LenthIsLessThan(const string& str, int len) { return str.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《《str《《endl; }};Func myFunc;myFunc(“helloworld!”);

》》》helloworld!

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

class StringAppend{ public: explicit StringAppend(const string& str) : ss(str){} void operator() (const string& str) const{ cout《《str《《‘ ’《《ss《《endl; } private: const string ss; }; StringAppend myFunc(“is world”); myFunc(“hello”);

》》》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的资料和个人学习心得。

-END-

来源 | dnbc66

责任编辑:haq

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

    关注

    3

    文章

    3904

    浏览量

    61310
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72901
收藏 人收藏

    评论

    相关推荐

    C/C++代码动态测试工具VectorCAST插桩功能演示#代码动态测试 #C++

    C++代码
    北汇信息POLELINK
    发布于 :2024年04月18日 11:57:45

    什么是C++函数? 应该怎么定义? 用途是什么?

    什么是C++函数? 应该怎么定义? 主要用途是什么?
    发表于 11-08 06:58

    C++程序设计精简版

    章 指针第 7 章 自定义数据类型 第 3 篇 基于对象的程序设计第 8 章 类和对象第 9 章 关于类和对象的进一步讨论第 10 章 运算符重载 第 4 篇 面向对象的程序设计第 11 章 继承与派生第 12 章 多态性与虚函数第 13 章 输入输出流第 14 章
    发表于 10-09 07:26

    C++生成Dll与回调函数测试

    描述了VS环境下,通过C++生成dll的方法,测试回调函数
    的头像 发表于 08-29 16:05 643次阅读
    <b class='flag-5'>C++</b>生成Dll与回调<b class='flag-5'>函数</b>测试

    适用于µVision的ARM编译器工具链v5.02 ARM CC++库及浮点支持参考

    下列主题介绍标准CC++函数,这些函数C标准的扩展或在某种程度上与标准不同。 一些标准函数
    发表于 08-18 06:35

    如何为原生C++开发设置Android Studio

    意味着使用函数重用代码。 但是,调用函数会增加额外的开销。 为了减少这种开销,编译器利用称为内部函数的内置函数。 编译器将高级编程语言(例如C
    发表于 08-17 08:28

    _C_调用函数_第2节

    函数C++
    充八万
    发布于 :2023年08月11日 11:34:59

    如何为Arm编译Cc++代码

    编写CC++应用程序时,需要使用编译器工具链将其编译为机器代码。然后,您可以在基于Arm的处理器上运行此编译的可执行代码,或者使用模型对其进行模拟。 裸机编译编译器工具链包括以下组件: •将C
    发表于 08-02 17:28

    使用C++ sort函数对vector进行自定义排序

    今天在学一些C++ STL容器,看到sort函数允许自定义排序规则,小小地实操了一下。
    的头像 发表于 07-22 10:12 1057次阅读

    C++ std::tie函数的作用和用法

    C++中std::tie函数的作用就是从元素引用中生成一个tuple元组,其在头文件中定义
    的头像 发表于 07-18 17:28 573次阅读

    c++函数对象与内建函数

    重载函数调用操作的类,其对象常称之为函数对象。
    的头像 发表于 07-17 09:46 356次阅读
    <b class='flag-5'>c++</b>之<b class='flag-5'>函数</b>对象与内建<b class='flag-5'>函数</b>

    一起探索C++的世界!

    C++
    YS YYDS
    发布于 :2023年07月07日 19:10:25

    嵌入式-C++函数的重载

    一、什么是函数的重载 两个以上的函数,具有相同的函数名,通过参数的类型和参数的个数不同。编译器自行匹配,自动确定调用哪一个函数 二、函数重载
    发表于 06-28 13:54

    如何为xtensa编译C++

    我想为 xtensa 编译简单的 C++ 代码,但我不能。 代码:全选#include \"ets_sys.h\" #include \"osapi.h\"
    发表于 06-09 07:02

    c++常见函数

    c++常见函数集包括:线性代数方程组的解法、插值、数值积分、特殊函数函数逼近、随机数排序、特征值问题、数据拟合、方程求根和非线性方程组的解法、函数
    发表于 05-09 14:52 1次下载