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

目录

简介

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

std::function

std::function对象包装器

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

cpp 复制代码
#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做回调函数

cpp 复制代码
#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绑定普通函数

cpp 复制代码
#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是一个占位符,表示这个位置将在函数调用时,被传入的第一个参数替代。

占位符的使用方法

cpp 复制代码
#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可以绑定成员函数和成员变量。其中绑定成员函数和绑定普通函数时是有一些差别的。

cpp 复制代码
#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 绑定成员函数时,需要注意以下几点:

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

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

相关推荐
L_09074 分钟前
【C++】数据结构之哈希表(散列表)
数据结构·c++·散列表
LB211211 分钟前
C++通讯录课设(西安石油大学)
开发语言·c++·算法
王老师青少年编程12 分钟前
2026年全国青少年信息素养大赛初赛真题(算法应用主题赛C++初中组初赛真题1:文末附答案和解析)
c++·真题·全国青少年信息素养大赛·初赛·2026年·算法应用主题赛·初中组
专注VB编程开发20年1 小时前
python语法设计、IDE 生态、平台策略、解析器逻辑这四层的矛盾点
开发语言·ide·python
草莓熊Lotso2 小时前
【Linux系统加餐】从原理到封装:基于建造者模式实现System V信号量工业级C++封装
android·linux·运维·服务器·网络·c++·建造者模式
潜创微科技9 小时前
IT6520:USB‑C 转 MIPI 芯片方案 4K@120Hz 高清显示
c语言·开发语言
言之。10 小时前
【Python】免费的中文 AI 配音方案
开发语言·人工智能·python
kyle~10 小时前
机器视觉---熔池相机(穿透强光的视觉感知)
c++·数码相机·计算机视觉·机器人·焊接机器人
宏笋10 小时前
C++ Coroutines(协程) 详解
c++
天天进步201510 小时前
Python全栈项目:从零手操一个高性能 API 网关
开发语言·python