简体   繁体   English

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

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

As mentioned in a similarly worded question ( Why use bind over lambdas in c++14? ) The answer was - no reason (and also mentioned why it would be better to use lambdas).正如措辞相似的问题( Why use bind over lambdas in c++14? )中提到的那样,答案是 - 没有理由(并且还提到了为什么使用 lambdas 会更好)。

My question is - if in C++14 there was no longer a reason to use bind, why did the standards committee found it necessary to addstd::bind_front in C++20?我的问题是 - 如果在 C++14 中不再有使用绑定的理由,为什么标准委员会发现有必要在 C++20 中添加std::bind_front

Does it now have any new advantage over a lambda?它现在比 lambda 有什么新的优势吗?

bind_front binds the first X parameters, but if the callable calls for more parameters, they get tacked onto the end. bind_front绑定第一个 X 参数,但如果可调用对象调用更多参数,它们将被添加到末尾。 This makes bind_front very readable when you're only binding the first few parameters of a function.当您只绑定 function 的前几个参数时,这使得bind_front非常可读。

The obvious example would be creating a callable for a member function that is bound to a specific instance:一个明显的例子是为绑定到特定实例的成员 function 创建一个可调用对象:

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);

The bind_front version is a lot less noisy. bind_front版本的噪音小得多。 It gets right to the point, having exactly 3 named things: bind_front , the member function to be called, and the instance on which it will be called.它直截了当,有 3 个命名的东西: bind_front ,要调用的成员 function ,以及将在其上调用它的实例。 And that's all that our situation calls for: a marker to denote that we're creating a binding of the first parameters of a function, the function to be bound, and the parameter we want to bind.这就是我们的情况所需要的:一个标记,表示我们正在创建 function 的第一个参数的绑定,要绑定的 function 以及我们要绑定的参数。 There is no extraneous syntax or other details.没有多余的语法或其他细节。

By contrast, the lambda has a lot of stuff we just don't care about at this location.相比之下,lambda 在这个位置有很多我们不关心的东西。 The auto... args bit, the std::forward stuff, etc. It's a bit harder to figure out what it's doing, and it's definitely much longer to read. auto... args位, std::forward东西等。弄清楚它在做什么有点困难,而且阅读起来肯定要长得多。

Note that bind_front doesn't allow bind 's placeholders at all, so it's not really a replacement.请注意, bind_front根本不允许bind的占位符,因此它并不是真正的替代品。 It's more a shorthand for the most useful forms of bind .它更像是bind最有用的 forms 的简写。

The paper that proposed it Simplified partial function application has some good compelling use cases.提出简化部分 function 应用程序的论文有一些很好的引人注目的用例。 I will summarize them here, because otherwise I would have to quote most of the paper, so definitely go check it out:我将在这里总结它们,因为否则我将不得不引用大部分论文,所以一定要 go 看看:

Automatic perfect forwarding自动完美转发

Using a lambda would involve std::forward boilerplate使用 lambda 将涉及std::forward样板

Propagating mutability传播可变性

In case of storing object by value std::bind and std::bind_front propagate constness, but in the case of capturing lambda the user must chose a mutable or const version creating problems如果通过值std::bindstd::bind_front存储 object 传播常量,但在捕获 lambda 的情况下,用户必须选择可变或常量版本,从而产生问题

Preserving return type保留返回类型

Using a lambda would involve -> decltype(auto) boilerplate on the user side.在用户端使用 lambda 将涉及-> decltype(auto)样板。

Preserving value category保值类

Like preserving mutability, except now we are talking about lvalue/rvalue and only std::bind_front does this correctly就像保留可变性一样,除了现在我们谈论的是左值/右值并且只有std::bind_front正确地做到这一点

Supporting one-shot invocation支持一次性调用

A consequence of propagating mutability and preserving value category传播可变性和保留值类别的结果

Preserving exception specification保留异常规范

This is especially more important now since exception specification is now part of type system这一点现在尤其重要,因为异常规范现在是类型系统的一部分


cppreference has some useful notes as well: cppreference也有一些有用的注释:

This function is intended to replace std::bind.此 function 旨在替换 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.与 std::bind 不同,它不支持任意参数重新排列,并且对嵌套的绑定表达式或 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.另一方面,它关注调用包装器 object 的值类别,并传播底层调用运算符的异常规范。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM