【问题标题】:Why use `std::bind_front` over lambdas in C++20?为什么在 C++20 中使用 `std::bind_front` 而不是 lambda?
【发布时间】:2020-10-29 15:04:57
【问题描述】:

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

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

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

【问题讨论】:

    标签: c++ lambda c++20 stdbind bind-front


    【解决方案1】:

    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 的占位符,因此它并不是真正的替代品。它更像是bind 最有用形式的简写。

    【讨论】:

    • 值得注意的是,bind_front 带来的优化器优势比 bind 的所有花里胡哨更简单、更受限制。更小的实现,优化器应该很容易看穿。
    【解决方案2】:

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

    自动完美转发

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

    传播可变性

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

    保留返回类型

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

    保值类

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

    支持一次性调用

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

    保留异常规范

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


    cppreference 也有一些有用的注释:

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

    【讨论】:

      猜你喜欢
      • 2020-08-06
      • 1970-01-01
      • 2020-10-01
      • 2021-05-24
      • 2021-12-02
      • 1970-01-01
      • 2021-01-10
      • 2018-01-09
      相关资源
      最近更新 更多