C++11新特性④ | 模板类std::function和标准库函数std::bind

目录

1、引言

2、std::function函数模板类

3、std::bind标准库函数

4、std::bind和std::function配合使用


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html       C++11新特性很重要,作为C++开发人员很有必要去学习,不仅笔试面试时会涉及到,开源代码中也在大规模的使用。以很多视频会议及直播软件都在使用的开源WebRTC项目为例,WebRTC代码中大篇幅地使用了C++11及以上的新特性,要读懂其源码,必须要了解这些C++的新特性。所以,接下来一段时间我将结合工作实践,给大家详细讲解一下C++11的新特性,以供借鉴或参考。

1、引言

       C++11引入了一个模板类std::function以及一个标准库函数std::bind,这两个特性使得C++变得更加灵活。使用std::function类模板可以实现对调用对象的包装。调用标准库函数std::bind在原有函数的基础上生成一个新的函数,方便调用。下面就来详细讲解这两个新特性。

2、std::function函数模板类

       在C++中,可调用实体主要包括:函数、函数指针、函数引用、可以隐式转换为函数指定的对象,或者实现了opetator()的对象。

       C++11中,新增加了一个std::function类模板,它是对C++中现有的可调用实体的一种类型安全的包裹。std::function可以存储,复制和调用任何可调用目标的实例,例如函数,lambda表达式,绑定表达式或其他函数对象,以及指向成员函数和指向数据成员的指针。通过指定它的模板参数,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们。

       该模板类中所存储的可调用对象被称为目标的std::function。如果一个std::function实例不包含目标,则将其称为空。调用空的std::function对象会导致抛出异常std::bad_function_call。

#include <iostream>
#include <functional>   //std::cout
using namespace std;void func(void)
{//普通全局函数cout << __func__ << endl;
}class Foo
{
public:static int foo_func(int a){//类中静态函数cout << __func__ << "(" << a << ") ->: ";return a;}
};class Bar
{
public:int operator()(int a){//仿函数cout << __func__ << "(" << a << ") ->: ";return a;}
};int main()
{//绑定一个普通函数function< void(void) > f1 = func;f1();//绑定类中的静态函数function< int(int) > f2 = Foo::foo_func;cout << f2(111) << endl;//绑定一个仿函数Bar obj;f2 = obj;cout << f2(222) << endl;/*运行结果:funcfoo_func(111) ->: 111operator()(222) ->: 222*/return 0;
}

std::function对象最大的用处就是在实现函数回调,使用者需要注意,它不能被用来检查相等或者不相等,但是可以与NULL或者nullptr进行比较。

3、std::bind函数

       std::bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体,这种机制在回调函数的使用过程中也颇为有用。

C++98中,有两个函数bind1st和bind2nd,它们分别可以用来绑定functor的第一个和第二个参数,它们都是只可以绑定一个参数,各种限制,使得bind1st和bind2nd的可用性大大降低。

       在C++11中,提供了std::bind,它绑定的参数的个数不受限制,绑定的具体哪些参数也不受限制,由用户指定,这个bind才是真正意义上的绑定。可以将bind函数看成一个通用的函数适配器,它接收一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。调用bind的一般形式:

auto newCallable = bind( callable,  arg_lsit);

其中,newCallable是个可调用对象,arg_lsit是一个逗号分隔的参数列表,对应给callable可调用对象传递的参数。当我们调用新的newCallable时,newCallable会调用callable,并将arg_lsit中的参数传递给callable。

       此外,arg_lsit中的参数可能包含形式如_n的名字,其中n是个整数,这样的参数是“占位符”,是传递给newCallable的第n个参数。_n是定义在名为placeholders的命名空间中的,这个命名空间位于std空间中,所以_1对应的using声明为:

using std::placeholders::_1。

         下面举一个使用bind函数替换lambda表达式的例子。比如有个存放string对象的vector列表:

std::vector<string> strList;

使用lambda表达式查找列表中字符串长度大于等于6的元素:

DWORD dwLen = 6;
find_if( strList.begin(), strList.end(), [dwLen](const string & str )
{ str.size() >= dwLen;}); // 使用lambda表达式

用lambda函数实现比较简单。

       如果要用一个普通函数去比较字符串长度,如何去调用find_if呢?比如检测字符串长度的函数如下:

bool CheckStrLen( const string& str,  DWORD dwLen )
{return str.size() >= dwLen;
}

因为给find_if传入的比较函数只有一个参数,而此处的比较函数有两个参数,所以没法直接传入。我们可以使用bind函数去构建一个新的函数:

DWORD dwLen = 6;
auto CheckStrLenBind = bind( CheckStrLen, _1, dwLen );  // 调用CheckStrLenBind,就会调用CheckStrLen,然后给CheckStrLen传递两个参数

此处以一个字符串作为例子,看看bind函数调用过程:

DWORD dwLen = 6;
auto CheckStrLenBind = bind( CheckStrLen, _1, dwLen ); 
string str = “hello”;
bool bRet = CheckStrLenBind( str ); // 此处相当于调用CheckStrLen(str, dwLen)

所以,调用find_if时可以这样写:

DWORD dwLen = 6;
auto CheckStrLenBind = bind( CheckStrLen, _1, dwLen ); 
find_if(  strList.begin(), strList.end(), CheckStrLenBind);

find_if给CheckStrLenBind传入一个string类对象,然后CheckStrLenBind将这个string类对象作为第一个参数传给最终的函数CheckStrLen,同时将dwLen传给CheckStrLen。

       也可以直接这样写:

find_if(  strList.begin(), strList.end(), bind( CheckStrLen, _1, dwLen ));

4、std::bind和std::function配合使用

       我们也可以将std::bind和std::function配合起来使用,这样所有的可调用对象均有了统一的操作方法。看下面的例子:

#include <iostream>
#include <functional>   //std::cout
using namespace std;
using namespace std::placeholders;    // adds visibility of _1, _2, _3,...class Test
{
public:int i = 0;void func(int x, int y){cout << x << " " << y << endl;}
};int main()
{Test obj; //创建对象function<void(int, int)> f1 = bind(&Test::func, &obj, _1, _2);f1(1, 2);   //输出:1 2function< int &()> f2 = bind(&Test::i, &obj);f2() = 123;cout << obj.i << endl;//结果为 123return 0;
}

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

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

相关文章

安全测试 —— 你了解WEB安全测试吗?

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

计算机网络-谢希任第八版学习笔记总结

一.计算机网络概述 21世纪三个特点 数字化 信息化 智能化&#xff0c;其中主要是围绕智能化。 网络的常见分类&#xff1a; 电话网络 有线电视网络 计算机网络 互联网&#xff1a;Internet 由数量极大的计算机网络相连接 特点&#xff1a; 共享性 连通性 互联网&…

WINGREEN 034STN1-01-300-R 传感器模块

WINGREEN 034STN1-01-300-R 是一种传感器模块&#xff0c;通常用于监测和采集各种环境或过程参数的数据。以下是这种类型的传感器模块通常可能具备的一般功能和特点&#xff1a; 传感器接口&#xff1a;模块通常配备用于连接不同类型传感器的接口&#xff0c;如温度传感器、湿度…

好玩的js特效

记录一些好玩的js特效 1、鱼跳跃特效 引入jquery:https://code.jquery.com/jquery-3.7.1.min.js 源码如下&#xff1a; <!--引入jquery--> <script src"https://code.jquery.com/jquery-3.7.1.min.js"></script> <!--引入跳跃源码--> <s…

第三方软件信息安全测评服务范围

安全测试 第三方软件信息安全cnas资质测评服务范围&#xff1a; 1、信息安全风险评估 依据《GB/T 20984-2007 信息安全技术信息安全风险评估规范》&#xff0c;通过风险评估项目的实施&#xff0c;对信息系统的重要资产、资产所面临的威胁、资产存在的脆弱性、已采取的防护措…

aarch64 arm64 部署 stable diffusion webui 笔记 【1】准备 venv 安装pytorch 验证cuda

aarch64 pytorch(没有aarch64对应版本&#xff0c;自行编译) pytorch-v2.0.1 cuda arm64 aarch64 torch 2.0.1cu118 源码编译笔记【2】验证cuda安装 成功_hkNaruto的博客-CSDN博客 创建venv [rootceph3 stable-diffusion-webui]# /usr/local/Python-3.10.12/bin/python3 -m v…

Python 03(循环语句)

Python03&#xff08;循环语句&#xff09; 文章目录 Python03&#xff08;循环语句&#xff09;一、while语句二、while实现猜数字三、while循环的嵌套while循环嵌套实例需求&#xff1a; 四、for循环1、什么 是for循环2、语法3、执行流程4、for循环的基本使用5、range()函数6…

【Python】Python运算符/部分函数对应的双下划线魔法方法

先说下Python版本&#xff1a;【Python 3.7.8】 以下用图片表格展示&#xff0c;一是防扒&#xff0c;二是没精力改成md格式。 还有就是内容肯定没有完全包含(而且也很难做到)&#xff0c;像是__reduce__与py自带模块pickle有关(pickle用于对象序列化/反序列化)、sys.getsizeo…

武汉凯迪正大—直读激光盐密灰密测试仪

一、凯迪正大—绝缘子灰密盐密测试仪产品概述 凯迪正大绝缘子灰密盐密测试仪采用的检测技术将灰密测试与盐密测试合二为一&#xff0c;可同时检测出被测绝缘子的灰密度和盐密度&#xff0c;简化了绝缘子污秽检测的流程&#xff0c;适合在巡检现场和实验室使用。 二、凯迪正大…

OpenCV(三十一):形态学操作

​​​​​​1.形态学操作 OpenCV 提供了丰富的函数来进行形态学操作&#xff0c;包括腐蚀、膨胀、开运算、闭运算等。下面介绍一些常用的 OpenCV 形态学操作函数&#xff1a; 腐蚀操作&#xff08;Erosion&#xff09;&#xff1a; erode(src, dst, kernel, anchor, iteration…

关于 Unity 连接 MuMu 模拟器上的 Unity Remote 5 的方法

在使用 Unity 开发 Android 的过程中&#xff0c;可以通过使用 Unity Remote 这个 app 来和真机连接&#xff0c;进而在真实环境下进行测试性能等工作&#xff0c;而本次则是由于其他问题引出的一个小坑&#xff0c;记录以备后续查询。 这次是由于在自学过程中遇到的一个工程&…

go-zero jwt 鉴权快速实战

前面我们分享了 go-zero 的快速实战以及日志组件的剖析&#xff0c;本次我们来实战使用 go-zero jwt 鉴权 本次文章主要是分享关于 go-zero 中 jwt 的使用方式&#xff0c;会以一个 demo 的方式来进行实战&#xff0c;对于使用 goctl 工具以及安装细节就不在赘述&#xff0c;有…