C++11实用技术(二)std::function和bind绑定器

简介: C++11实用技术(二)std::function和bind绑定器


简介

C++11新增了std::function和std::bind。用于函数的包装以及参数的绑定。可以替代一些函数指针回调函数的场景。

std::function

std::function对象包装器

std::function是可调用对象的包装器,它可以用来用统一的方式来处理函数、函数对象、函数指针,并允许保存和延迟执行它们。比较难理解,可以从代码上深入:

#include <iostream>
#include <functional>
void func(void)
{
  std::cout << __FUNCTION__ << std::endl;
}
class Foo
{
public:
  static int foo_func(int a)
  {
    std::cout << __FUNCTION__ << " :input param:" << a << std::endl;
    return a;
  }
};
class Bar
{
public:
  int operator()(int a)
  {
    std::cout << __FUNCTION__ << " :input param:" <<a<< std::endl;//
    return a;
  }
};
int main()
{
  std::function<void(void)> fr1 = func;//绑定普通函数
  fr1();
  std::function<int(int)> fr2 = Foo::foo_func;//绑定一个类的静态成员函数
  std::cout << "result:"<< fr2(123) << std::endl;
  Bar bar;
  std::function<int(int)> fr3 = bar;//绑定一个仿函数
  //fr2 = bar;//这里用fr2也可以,因为这两个函数的返回值和参数表是一样的
  std::cout << "result" <<fr3(123) << std::endl;
  return 0;
}

注意:代码中__FUNCTION__是预定义标识符,基本功能是实现返回所在函数的名字,便于调试日志打印。

运行结果:

可以看出使用给std::function赋值上对应的函数返回值和函数参数表,它就可以容纳这一类调用方式的函数,被称为“函数包装器”。如上述的fr2可以容纳Foo::foo_func和bar。

这里可以看出function类似于函数指针的作用,可以保存各种类型的函数地址。

std::function做回调函数

#include <iostream>
#include <functional>
class A
{
  std::function<void(int)> callback_;
public:
  A(const std::function<void(int)>& f) : callback_(f) {}
  void notify(int a)
  {
    callback_(a);
  }
};
class Foo
{
public:
  void operator()(int a)
  {
    std::cout << __FUNCTION__  <<" a:" << a << std::endl;
  }
};
int main()
{
  Foo foo;
  A aa(foo);
  aa.notify(111);
  return 0;
}

这里可以看出function可以取代函数指针的作用,可以用function保存函数延迟执行,所有比较适合用在回调函数场景。

std::bind绑定器

std::bind可以将可调用对象和其参数一起绑定,绑定后的结果可以用std::function进行保存。

其中绑定普通函数和绑定成员函数的写法有所不同。

bind绑定普通函数

#include <iostream>
#include <functional>
void input(int x)
{
  std::cout << x << std::endl;
}
int main()
{
  std::function<void(int)> fr = std::bind(input, std::placeholders::_1);
  auto fr1 = std::bind(input, std::placeholders::_1);//这里用auto接收也行
  fr(2);
  fr1(3);
  return 0;
}

其中std::placeholders::_1是一个占位符,表示这个位置将在函数调用时,被传入的第一个参数替代。

占位符的使用方法

#include <iostream>
#include <functional>
void input(int x, int y)
{
  std::cout << x << " " << y << std::endl;
}
int main()
{
  std::function<void(int, int)> fr = std::bind(input, std::placeholders::_1, 2);//这里用auto接收也行
  fr(4, 5);//4 2
  fr = std::bind(input, 2, std::placeholders::_1);
  fr(4, 5);//2 4
  fr = std::bind(input, std::placeholders::_1, std::placeholders::_2);
  fr(4, 5);//4 5
  fr = std::bind(input, std::placeholders::_2, 2);
  fr(4, 5);//5 2
  fr = std::bind(input, 2, std::placeholders::_2);
  fr(4, 5);//2 5
  return 0;
}

结果:

在绑定参数时,可以通过占位符std::placeholders来决定空位参数会属于调用发生时的第几个参数。

bind绑定成员函数

bind可以绑定成员函数和成员变量。其中绑定成员函数和绑定普通函数时是有一些差别的。

#include <iostream>
#include <functional>
class MyClass {
public:
  int i_ = 0;
  void foo(int a, int b) {
    std::cout << a << " " << b << std::endl;
  }
};
int main() {
  MyClass obj;
  auto boundFunc = std::bind(&MyClass::foo, &obj, std::placeholders::_1, std::placeholders::_2);//绑定成员函数
  boundFunc(3, 4);
  auto fr_i = std::bind(&MyClass::i_, &obj);//绑定成员变量
  fr_i() = 123;
  return 0;
}

当使用 std::bind 绑定成员函数时,需要注意以下几点:

  • 需要使用成员函数的指针或函数对象来进行绑定。对于指针,需要使用 & 取址符号获取成员函数的地址。
  • 需要提供对象的指针(或引用)作为第一个参数,以便在调用时正确地调用成员函数。

可以看到绑定普通函数时是不需要提供对象的指针或引用作为参数。

目录
相关文章
|
18天前
|
存储 前端开发 安全
C++一分钟之-未来与承诺:std::future与std::promise
【6月更文挑战第27天】`std::future`和`std::promise`是C++异步编程的关键工具,用于处理未完成任务的结果。`future`代表异步任务的结果容器,可阻塞等待或检查结果是否就绪;`promise`用于设置`future`的值,允许多线程间通信。常见问题包括异常安全、多重获取、线程同步和未检查状态。解决办法涉及智能指针管理、明确获取时机、确保线程安全以及检查未来状态。示例展示了使用`std::async`和`future`执行异步任务并获取结果。
27 2
|
2月前
|
存储 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(下)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
39 5
|
19天前
|
安全 JavaScript 前端开发
C++一分钟之-C++17特性:结构化绑定
【6月更文挑战第26天】C++17引入了结构化绑定,简化了从聚合类型如`std::tuple`、`std::array`和自定义结构体中解构数据。它允许直接将复合数据类型的元素绑定到单独变量,提高代码可读性。例如,可以从`std::tuple`中直接解构并绑定到变量,无需`std::get`。结构化绑定适用于处理`std::tuple`、`std::pair`,自定义结构体,甚至在范围for循环中解构容器元素。注意,绑定顺序必须与元素顺序匹配,考虑是否使用`const`和`&`,以及谨慎处理匿名类型。通过实例展示了如何解构嵌套结构体和元组,结构化绑定提升了代码的简洁性和效率。
35 5
|
20天前
|
安全 C++
C++一分钟之-字符串处理:std::string
【6月更文挑战第25天】`std::string`是C++文本处理的核心,存在于`&lt;string&gt;`库中。它支持初始化、访问、连接、查找、替换等操作。常见问题包括空指针解引用、越界访问和不当内存管理。要安全使用,确保字符串初始化,用`at()`检查边界,用`.empty()`检查空字符串,且无需手动释放内存。高效技巧包括预先分配内存、利用互转函数以及使用迭代器。记得正确比较和遍历字符串以保证代码效率和安全性。
38 5
|
19天前
|
存储 设计模式 安全
C++一分钟之-并发编程基础:线程与std::thread
【6月更文挑战第26天】C++11的`std::thread`简化了多线程编程,允许并发执行任务以提升效率。文中介绍了创建线程的基本方法,包括使用函数和lambda表达式,并强调了数据竞争、线程生命周期管理及异常安全等关键问题。通过示例展示了如何用互斥锁避免数据竞争,还提及了线程属性定制、线程局部存储和同步工具。理解并发编程的挑战与解决方案是提升程序性能的关键。
37 3
|
1月前
|
C++
c++中的using namespace std;
c++中的using namespace std;
|
2月前
|
算法 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(中)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
29 2
|
2月前
|
算法 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(上)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
19 1
|
3天前
|
设计模式 安全 编译器
【C++11】特殊类设计
【C++11】特殊类设计
22 10
|
8天前
|
C++
C++友元函数和友元类的使用
C++中的友元(friend)是一种机制,允许类或函数访问其他类的私有成员,以实现数据共享或特殊功能。友元分为两类:类友元和函数友元。类友元允许一个类访问另一个类的私有数据,而函数友元是非成员函数,可以直接访问类的私有成员。虽然提供了便利,但友元破坏了封装性,应谨慎使用。
39 9

热门文章

最新文章