C++11系列学习之可调用对象包装器和绑定器

目录
  • 旧标准的缺陷
    • 繁杂的调用对象
    • 问题浮出水面
  • std::function
    • 小试牛刀
  • std::bind
    • 作用
    • 占位符
    • 高级用法
  • 配合使用

旧标准的缺陷

学习新标准的语法之前,先来聊聊旧标准存在的缺陷,这样就可以理解为什么要在C++11中存在std::funtionstd::bind了,这就是所谓——知其然,并知其所以然

繁杂的调用对象

C++中可以调用的对象有很多,包括但不限于以下:

  • 函数指针
  • 仿函数(重载了"( )" 运算符)
  • 可被转换为函数指针的类对象
  • 类成员函数

问题浮出水面

这些调用对象在使用的时候具有比较统一的时候,但是定义的方式却是五花八门。因此,C++11中为了改善这个问题,提供了std::functionstd::bind来解决

std::function

std::function是可调用对象的包装器本质上是一个类模板可容纳除了类成员(函数)指针之外的所有可调用对象

小试牛刀

#include<iostream>
#include<functional>
class A
{
std::function<void()> callback_;
public:
A(const std::function<void()>& f) : callback_(f){}
void notify(void){
callback_(); //调用这个回调对象
}
};
class Foo{
public:
void operator()(void){
std::cout << __FUNCTION__ << std::endl;
}
};
int main(void)
{
Foo foo;
A aa(foo);
aa.notify(); //调用这个回调
return 0;
}
//输出
//operator()

std::function因为有着保存函数并可以延迟执行的特性,因此非常适合作为回调函数来使用

std::bind

std::bind用来将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function进行保存,并延迟调用

作用

  • 将可调用对象与其参数一起绑定成一个仿函数
  • 将N元可调用对象转换成一元或N-1元可调用对象,即只绑定部分参数

占位符

std::bind可以将函数及其参数进行绑定,那么参数的位置与传入的位置相关,因此有了占位符的概念,例如std::placeholders::_1是第一个参数的占位符,当函数传入第一个参数的时候,就会把其进行替换,同理std::palceholders::_2是第二个占位符。

#include<iostream>
#include<functional>
void output(int x, int y){
std::cout << x << " " << y << std::endl;
}
int main(){
std::bind(output, 1, 2)(); //输出:1 2
std::bind(output, std::placeholders::_1)(1); //输出:1
std::bind(output, 2, std::placeholders::_2)(1,2); //输出:2 2
std::bind(output, std::placeholders::_2, std::placeholders::_1)(1, 2); //输出:2 1
}

高级用法

可以使用std::bind进行多个函数的组合,例如找出集合中大于5小于10的元素个数:

#include<iostream>
#include<functional>
using std::placeholders::_1;
auto f = std::bind(std::logical_and<bool>(), std::bind(std::greater<int>(), _1, 5),std::bind(std::less_equal<int>(), _1, 10)); //将两个函数参数绑定并进行组合
int count = std::count_if(coll.begin(), coll.end(), f); //使用

配合使用

std::bindstd::function配合使用非常的强大

#include<iostream>
#include<funcational>
class A{
public:
int i_ = 0;
void output(int x, int y){
std:cout << x << " " << y << std::endl;
}
};
int main(void){
A a;
std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1,std::palceholders::_2); //注意
fr(1, 2); //输出:1 2
std::function<int&(void)> fr_i = std::bind(&A::i, &a);
fr_i() = 123;
std::cout << a.i_ << std::endl; //输出:123
}

可以看到上面std::bind在绑定类的成员函数的时候,需要把&a也传进去,这是因为成员函数编译器在使用的时候会自动传入一个this指针,所以我们绑定的时候需要额外传一个对象的地址

到此这篇关于C++11系列学习之可调用对象包装器和绑定器的文章就介绍到这了,更多相关C++11包装器和绑定器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++11 学习笔记之std::function和bind绑定器

    std::function C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法五花八门.为了统一泛化函数对象,函数指针,引用函数,成员函数的指针的各种操作,让我们可以按更统一的方式写出更加泛化的代码,C++11推出了std::function. std::function是可调用对象的包装器.它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象.通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟

  • C++11/14 线程调用类对象和线程传参的方法

    线程调用类对象 在前面的示例中,我们为线程任务使用了通常的函数.实际上,我们可以使用任何可调用对象或者lambda函数,如下调用类对象的例子: #include <iostream> #include <thread> class MyFunctor { public: void operator()() { std::cout << "functor\n"; } }; int main() { MyFunctor fnctor; std::thre

  • C++11系列学习之可调用对象包装器和绑定器

    目录 旧标准的缺陷 繁杂的调用对象 问题浮出水面 std::function 小试牛刀 std::bind 作用 占位符 高级用法 配合使用 旧标准的缺陷 学习新标准的语法之前,先来聊聊旧标准存在的缺陷,这样就可以理解为什么要在C++11中存在std::funtion和std::bind了,这就是所谓——知其然,并知其所以然 繁杂的调用对象 C++中可以调用的对象有很多,包括但不限于以下: 函数指针 仿函数(重载了"( )" 运算符) 可被转换为函数指针的类对象 类成员函数 问题浮出水

  • C++中各种可调用对象深入讲解

    概述 一组执行任务的语句都可以视为一个函数,一个可调用对象.在程序设计的过程中,我们习惯于把那些具有复用性的一组语句抽象为函数,把变化的部分抽象为函数的参数. 函数的使用能够极大的极少代码重复率,提高代码的灵活性. C++中具有函数这种行为的方式有很多.就函数调用方式而言 func(param1, param2); 这儿使用func作为函数调用名,param1和param2为函数参数.在C++中就func的类型,可能为: 普通函数 类成员函数 类静态函数 仿函数 函数指针 lambda表达式 C

  • ​​C++11系列学习之Lambda表达式

    目录 一.为什么要有lambda表达式? 二.使用语法 捕获列表 mutable影响lambda表达式 std::bind和lambda表达式结合 三.std::function 和lambda表达式选择 前言: 终于在C++11中引入了lambda表达式,lambda最早来源于函数式编程,现代语言慢慢都引入了这个语法,C++也不甘落后,在新标准中加入了lambda表达式. 一.为什么要有lambda表达式? 使用方便,就地声明函数或函数对象,尤其是和bind配合食用更佳 简洁,可以匿名创建,语

  • C++11系列学习之列表初始化

    目录 前言: 旧标准初始化方式 C++11标准初始化方式 初始化列表技术细节 总结 前言: 由于旧标准初始化方式太过繁杂,限制偏多,因此在新标准中统一了初始化方式,为了让初始化具有确定的效果,于是提出了列表初始化概念. 旧标准初始化方式 普通数组初始化: int i_arr[3] = {1, 2, 3} POD类型初始化(即plain old data类型,可以直接使用memcpy复制的对象): struct A { int x; struct B { int i; int j; } b; }

  • C++11中bind绑定器和function函数对象介绍

    目录 一. bind1st和bind2nd 1.C++ STL中的绑定器 2.bind1st和bind2nd的底层原理实现 二. 模板的完全特例化和非完全特例化 三. function函数对象 四. bind和function实现线程池 五. lambda表达式 1.lambda表达式的实现原理 2.lambda表达式的应用实践 一. bind1st和bind2nd 1.C++ STL中的绑定器 bind1st:operator()的第一个形参变量绑定成一个确定的值 bind2nd:operat

  • C++11系列学习之类型推导

    目录 auto类型推导 auto基本用法 auto 推导规则 auto 的限制 auto 适用场景 decltype 类型推导 decltype 基本用法 decltype 推导规则 decltype 适用场景 auto 和 decltype结合——返回类型后置 小结 auto类型推导 C++旧标准: 具有自动存储的局部变量 auto int i = 0 //C++98 实际上我们一般不这样写,因为非static变量默认就是具有自动存储的局部变量 C++11: 让编译器自动推断出这个变量的类型,

  • C++可调用对象callable object深入分析

    目录 为什么需要他 他究竟是啥 他怎样被使用呢 本作者一致的观点就是 在任何语言执行的时候先去思考汇编层面能不能做到 如果能做到 那么高级语言才能做到 无论你推出什么新特性 用户态汇编你都是绕不开的 比如你要调用函数 那么你必须要使用call指令 那么就必须要有函数地址 接下来我们来详细说说为什么c++11要推出这个新概念 以及他解决了什么问题 还有如何使用它 Tips:c++的设计哲学是你必须时刻清楚你自己在干什么 stl内部并不会给你执行任何的安全检查 程序直接崩溃也是完全有可能的 功力不够

  • Java的反射机制---动态调用对象的简单方法

    唉!我还真是在面试中学习新东东啊,一个公司刚刚给了个测试,不过我很奇怪的是为什么web developer的职位居然考java的反射机制题,不过学习研究一下反射机制对我来说是件好事啦! 先说说什么是java反射机制吧,在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这 种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.主要功能:在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对 象:在运行时判断任意一个

  • JavaScript词法作用域与调用对象深入理解

    关于 Javascript 的函数作用域.调用对象和闭包之间的关系很微妙,关于它们的文章已经有很多,但不知道为什么很多新手都难以理解.我就尝试用比较通俗的语言来表达我自己的理解吧. 作用域 Scope Javascript 中的函数属于词法作用域,也就是说函数在它被定义时的作用域中运行而不是在被执行时的作用域内运行.这是犀牛书上的说法.但"定义时"和"执行(被调用)时"这两个东西有些人搞不清楚.简单来说,一个函数A在"定义时"就是 functio

随机推荐