如同一个类似措辞的问题所提到的 (为什么在c++14中使用std::bind而不是lambda表达式?),答案是——没有理由(并且还提到了为什么使用lambda更好)。
我的问题是——如果在C++14中已经不需要使用bind了,为什么标准委员会觉得有必要在C++20中添加std::bind_front
呢?
现在它是否有任何新优势可以胜过lambda?
如同一个类似措辞的问题所提到的 (为什么在c++14中使用std::bind而不是lambda表达式?),答案是——没有理由(并且还提到了为什么使用lambda更好)。
我的问题是——如果在C++14中已经不需要使用bind了,为什么标准委员会觉得有必要在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::bind
和std::bind_front
传播constness,但在捕获lambda的情况下,用户必须选择创建问题的可变或不可变版本。
使用lambda会在用户端涉及到-> decltype(auto)
的样板文件。
与保留可变性相似,只是现在我们讨论的是lvalue/rvalue,并且只有std::bind_front
可以正确地处理它们。
这是传播可变性和保留值类别的结果。
现在异常规范已成为类型系统的一部分,这尤其重要。
cppreference也有一些有用的注释:
该函数旨在替换std::bind。与std::bind不同,它不支持任意参数重新排列,也没有针对嵌套的绑定表达式或std::reference_wrappers的特殊处理。另一方面,它关注调用包装对象的值类别,并且传播底层调用运算符的异常规格。
bind_front
带来了优化器的好处——它比使用带有各种花哨功能的bind
更加简单和受限。这样实现出来的代码要小得多,优化器可以更容易地进行优化。 - chris