C++ 23 实用工具(二)绑定工具

C++ 23 实用工具(二)绑定工具

267404

Adaptors for Functions

std::bindstd::bind_frontstd::bind_backstd::function这四个函数非常适合一起使用。

其中,std::bindstd::bind_frontstd::bind_back可以让您即时创建新的函数对象,而std::function则可以将这些临时的函数对象绑定到变量上。

然而,在C++中,这四个函数大多数情况下都是多余的。首先,您可以使用lambda表达式代替std::bindstd::bind_frontstd::bind_back;其次,您通常可以使用自动类型推导的auto关键字代替std::function

因此,尽管在某些特定场景下,这些函数仍然是有用的,但在大多数情况下,它们并不是必须的。

std::bind

#include <functional>
#include <iostream>

using namespace std::placeholders;

double divMe(double a, double b) { return a / b; };

int main()
{
	std::function<double(double, double)> myDiv1 = std::bind(divMe, _1, _2);
	std::function<double(double)> myDiv2 = std::bind(divMe, 2000, _1);
	std::function<double(double)> myDiv3 = std::bind_front(divMe, 2000);
	std::function<double(double)> myDiv4 = std::bind_back(divMe, 10);

	std::cout << "myDiv1(1000, 5) = " << myDiv1(1000, 5) << std::endl; // 200
	std::cout << "myDiv2(10) = " << myDiv2(10) << std::endl; // 200
	std::cout << "myDiv3(5) = " << myDiv3(5) << std::endl; // 400
	std::cout << "myDiv4(2000) = " << myDiv4(2000) << std::endl; // 200
	return 0;
}

借助std::bind,您可以以多种方式创建函数对象:

  • 将参数绑定到任意位置
  • 改变参数的顺序
  • 引入占位符
  • 部分求值函数

通过std::bind创建的新函数对象可以被调用、用于STL算法或者存储在std::function中。

std::bind_front (C++20)

std::bind_front函数可以从可调用对象创建可调用包装器。调用std::bind_front(func, arg...)会将所有参数arg绑定到func的前面,并返回一个可调用包装器。

std::bind_back (C++23)

std::bind_back函数可以从可调用对象创建可调用包装器。调用std::bind_back(func, arg...)会将所有参数arg绑定到func的后面,并返回一个可调用包装器。

std::function

std::function函数可以将任意可调用对象存储到变量中,它是一个多态的函数包装器。可调用对象可以是lambda函数、函数对象或者函数。如果需要显式指定可调用对象的类型,则必须使用std::function,它无法被auto关键字替换。

std::tie 和 std::ignore

std::tie函数可以创建引用变量的元组。当您需要同时返回多个值时,可以使用std::tie函数将这些值打包成一个元组返回,并通过引用将元组的内容解包到变量中。

例如,假设您有一个返回两个值的函数foo(),您可以使用std::tie函数将这两个值打包成一个元组返回,并通过引用将元组的内容解包到两个变量中:

int x, y;
std::tie(x, y) = foo();

如果您不需要元组中的某个元素,则可以使用std::ignore函数将其忽略。例如,假设您只需要元组中的第一个值,可以将第二个值用std::ignore函数忽略:

int x, y;
std::tie(x, std::ignore) = foo();

这样,foo()返回的元组中的第二个值将被忽略。

#include <tuple>
#include <iostream>

using namespace std;

int main()
{
	int first = 1;
	int second = 2;
	int third = 3;
	int fourth = 4;
	cout << first << " " << second << " " << third << " " << fourth << endl; // 1 2 3 4

	auto tup = std::tie(first, second, third, fourth) = std::make_tuple(101, 102, 103, 104); // 绑定元组并赋值
	cout << get<0>(tup) << " " << get<1>(tup) << " " << get<2>(tup) << " " << get<3>(tup) << endl; // 101 102 103 104
	cout << first << " " << second << " " << third << " " << fourth << endl; // 101 102 103 104

	first = 201;
	get<1>(tup) = 202;
	cout << get<0>(tup) << " " << get<1>(tup) << " " << get<2>(tup) << " " << get<3>(tup) << endl; // 201 202 103 104
	cout << first << " " << second << " " << third << " " << fourth << endl; // 201 202 103 104

	int a, b;
	tie(std::ignore, a, std::ignore, b) = tup;
	cout << a << " " << b << endl; // 202 104

	return 0;
}

Reference Wrappers

Reference Wrappers是一个定义在头文件中的可复制构造和可复制赋值的包装器,用于类型&的对象。它具有像引用一样的行为,但可以被复制。与传统引用不同,std::reference_wrapper对象支持两个附加用例:

  • 您可以在标准模板库的容器中使用它们。例如:std::vector<std::reference_wrapper<int>> myIntRefVector
  • 您可以复制具有std::reference_wrapper对象的类的实例。通常情况下,这对于引用是不可能的。

get成员函数允许访问引用:myInt.get()。您可以使用引用包装器来封装和调用可调用对象。

Reference Wrappers在处理需要使用引用的情况时非常有用,同时也允许在STL容器中存储引用类型的对象,这是传统引用无法做到的。因此,它是C++中一个非常方便的工具。

#include <functional>
#include <iostream>

void foo()
{
	std::cout << "被调用了" << '\n';
}

typedef void callableUnit();
std::reference_wrapper<callableUnit> refWrap(foo);

int main()
{
	refWrap(); // 输出 "被调用了"
	return 0;
}

这段代码定义了一个名为foo的函数,它没有参数和返回值。接下来,我们定义了一个名为callableUnit的函数类型别名,它代表没有参数和返回值的函数类型。然后,我们使用std::reference_wrapperfoo包装到refWrap中。

main函数中,我们直接调用refWrap(),这实际上会调用foo()函数并输出"被调用了"。由于refWrap是一个std::reference_wrapper对象,它可以像函数一样被调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值