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

fea*_*eer 48 c++ lambda stdbind c++20 bind-front

正如在一个类似措辞的问题中提到的(为什么在 c++14 中使用 bind over lambdas?)答案是 - 没有理由(并且还提到为什么使用 lambdas 会更好)。

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

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

Nic*_*las 53

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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 值得注意的是,“bind_front”带来的优化器优势比具有所有花哨功能的“bind”更简单、更受限制。更小的实现应该很容易让优化器看到。 (4认同)

bol*_*lov 39

提出它简化部分函数应用程序的论文有一些很好的引人注目的用例。我将在这里总结它们,否则我将不得不引用大部分论文,所以一定要去看看:

自动完美转发

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

传播可变性

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

保留返回类型

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

保值类

就像保持可变性一样,除了现在我们谈论的是左值/右值,而且只有std::bind_front这样做才正确

支持一次性调用

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

保留异常规范

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


cppreference也有一些有用的注释:

此函数旨在替换 std::bind。与 std::bind 不同,它不支持任意参数重排,并且对嵌套的绑定表达式或 std::reference_wrappers 没有特殊处理。另一方面,它关注调用包装对象的值类别并传播底层调用运算符的异常规范。