C++新特性 | bind & function

std::bind

概述

std::bind 是一个C++函数模板,简单说它就像一个函数适配器,用来接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。 该函数模板定义在头文件 #include <functional> 中。

C++中的可调用对象:函数、函数指针、lambda表达式、bind对象、函数对象。lambda表达式和bind对象是C++新标准中提出的,其他可调用对象在旧标准中就已存在。

bind 可以把一个原本接收 N 个参数的函数 origFunc(...),通过绑定(个人觉得此处的绑定让人难以理解 bind 的作用,感觉用固定或者给定更好理解)一些参数,返回一个接收 M 个(一般情况M小于N,当大于等于N时似乎多的参数没有实际意义)参数的新函数 newFunc(...)。同时,使用 std::bind 还可以实现参数顺序的调整等操作。

函数原型

// FUNCTION TEMPLATE bind (implicit return type)
template <class _Fx, class... _Types>
_NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
    return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}

// FUNCTION TEMPLATE bind (explicit return type)
template <class _Ret, class _Fx, class... _Types>
_NODISCARD _CONSTEXPR20 _Binder<_Ret, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
    return _Binder<_Ret, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}

上述函数原型为 VS2019 中的具体模板,可以看到 std::bind 有两种函数原型。

作用:用来返回基于 _Fx 的函数对象,参数被绑定到可变参数 _Args 中。每个参数都可以绑定到一个值或者一个占位符(bind 返回的 newFunc(..,) 的参数)。

bind 注意事项

  • bind 预先绑定的参数需要传递具体的变量或者值进去,对于预先绑定的参数,是通过值传递的。如果该参数被 std::ref 或者 std::cref 包装,则是通说引用传递。
  • bind 未预先绑定的参数,需要使用 std::placeholders(占位符),占位符从 _1 (表示原始可调用对象的第1个参数)开始递增。需要注意的是 std::placeholders 是按照引用传递的。
  • bind 绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址,这是因为对象的成员函数需要有 this 指针。并且编译器不会将对象的成员函数隐式转换成函数指针,需要通过 & 手动转换。
  • bind 返回值是可调用的实体,可以直接赋值给 std::function() 对象。
  • 对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的;类的this可以通过对象或者指针来绑定。

测试实例

#include <functional>
void addTwoNum(int a, int b) {
	cout << "a+b= " << a + b << endl;
}
struct INFOS {
	int year;
	int month;
	int day;
	void mergeDay() {
		string ret_str;
		ret_str = to_string(year) + "-" + to_string(month) + "-" + to_string(day);
		cout << "merged date info: " << ret_str << endl;
	}
};
int main() {
	// bind 绑定函数
	auto calSum = bind(addTwoNum, 1, std::placeholders::_1);
	calSum(10);
	auto calSum1 = bind(addTwoNum, 2, 3);
	calSum1();
	// bind 绑定函数成员对象
	INFOS information = {2022, 2, 23};
	auto dayInfos = bind(&INFOS::day, &information);
	cout << "day infos: " << dayInfos() << endl;
	auto mergeDate = bind(&INFOS::mergeDay, &information);
	mergeDate();

	INFOS infos = {2018, 8, 7};
	auto mergeDateUsNewParms = bind(&INFOS::mergeDay, std::placeholders::_1);
	mergeDateUsNewParms(infos);

	return 0;
}
/// Terminal output results:
a+b= 11
a+b= 5
day infos: 23
merged date info: 2022-2-23
merged date info: 2018-8-7

std::function

概述

由于可调用对象的定义方式较多,但是函数的调用方式较为类似,因此需要使用一个统一的方式保存可调用对象或者传递可调用对象。std::function 就可以实现该需求。

std::function 是一个通用的、多态的可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象(普通函数、Lambda表达式、函数指针、以及其它函数对象等),它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。可以对可以调用的目标实体进行存储、复制、和调用操作。

通过 std::function 可以形成一个新的可调用的std::function对象;让我们不再纠结那么多的可调用实体。

std::function 对象是对C++中现有的可调用实体的一种类型安全的包装(因为函数指针这类可调用实体,是类型不安全的)。

测试实例

int add(int a, int b) {
	return a + b;
}
auto multiply = [](int a, int b) {
	return a * b;
};
struct divs {
	int operator() (int a, int b) {
		return a / b;
	}
};

int main() {
	function<int(int, int)> addTwoNum = add;
	function<int(int, int)> multiTwoNum = multiply;
	function<int(int, int)> divTwoNum = divs();

	cout << addTwoNum(12, 23) << endl;
	cout << multiTwoNum(2, 4) << endl;
	cout << divTwoNum(12, 4) << endl;
	return 0;
}
/// Terminal output results:
35
8
3
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值