为什么在C++20中对lambdas使用"std::bind_front"

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

本文关键字:quot bind front std C++20 使用 为什么 中对 lambdas      更新时间:2023-10-16

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

我的问题是,如果在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版本噪音较小。它切中要害,正好有三个命名的东西:bind_front,要调用的成员函数,以及将在其上调用它的实例。这就是我们的情况所需要的:一个标记,表示我们正在创建函数的第一个参数、要绑定的函数和要绑定的参数的绑定。没有多余的语法或其他细节。

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

注意,bind_front根本不允许使用bind的占位符,所以它并不是真正的替代品。它更像是bind最有用形式的简写。

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

自动完美转发

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

传播可变性

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

保留返回类型

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

保值类别

就像保持可变性一样,只是现在我们谈论的是左值/右值,只有std::bind_front能正确地实现

支持一次性调用

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

保留异常规范

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


cppreference也有一些有用的注释:

此函数旨在取代std::bind。与std::bind不同,它不支持任意参数重排,并且没有特殊功能嵌套绑定表达式或std::reference_wrappers的处理。在…上另一方面,它关注呼叫的价值类别包装器对象,并传播的异常规范底层呼叫运营商。