为什么在 C++20 中使用 std::bind_front` 而不是 lambda?

Why use `std::bind_front` over lambdas in C++20?

正如措辞类似的问题 (Why use bind over lambdas in c++14?) 中提到的那样,答案是 - 没有理由(并且还提到了为什么使用 lambda 会更好)。

我的问题是 - 如果在 C++14 中不再有使用绑定的理由,为什么标准委员会发现有必要在 C++20 中添加 std::bind_front

它现在与 lambda 相比有什么新优势吗?

bind_front 绑定第一个 X 参数,但如果可调用函数调用更多参数,它们会被附加到最后。当您仅绑定函数的前几个参数时,这使得 bind_front 非常可读。

最明显的例子是为绑定到特定实例的成员函数创建可调用对象:

type *instance = ...;

//lambda
auto func = [instance](auto &&... args) -> decltype(auto) {return instance->function(std::forward<decltype(args)>(args)...);}

//bind
auto func = std::bind_front(&type::function, instance);

bind_front 版本噪音小 很多。它说到点子上了,恰好有 3 个命名的东西:bind_front,要调用的成员函数,以及将在其上调用它的实例。这就是我们的情况所需要的:一个标记来表示我们正在创建函数的第一个参数的绑定、要绑定的函数和我们想要绑定的参数。没有多余的语法或其他细节。

相比之下,lambda 在这个位置有很多我们不关心的东西。 auto... args 位,std::forward 等等。弄清楚它在做什么有点困难,而且阅读起来肯定要长得多。

请注意 bind_front 根本不允许使用 bind 的占位符,因此它并不是真正的替代品。它更像是 shorthand 最有用的形式 bind

提出它的论文 Simplified partial function application 有一些很好的引人注目的用例。我将在这里总结一下,否则我将不得不引用大部分论文,所以一定要去看看:

自动完美转发

使用 lambda 将涉及 std::forward 样板文件

传播可变性

在按值存储对象的情况下 std::bindstd::bind_front 传播常量,但在捕获 lambda 的情况下,用户必须选择可变或常量版本,这会产生问题

保留 return 类型

使用 lambda 将涉及 -> decltype(auto) 用户端的样板文件。

保值类

就像保留可变性一样,除了现在我们正在谈论 lvalue/rvalue 并且只有 std::bind_front 正确地做到了这一点

支持一次性调用

传播可变性和保留价值类别的结果

保留异常规范

这现在尤其重要,因为异常规范现在是类型系统的一部分


cppreference 也有一些有用的注释:

This function is intended to replace std::bind. Unlike std::bind, it does not support arbitrary argument rearrangement and has no special treatment for nested bind-expressions or std::reference_wrappers. On the other hand, it pays attention to the value category of the call wrapper object and propagates exception specification of the underlying call operator.