为什么在 C++14 中使用 std::bind 而不是 lambdas?

2021-12-23 00:00:00 lambda bind c++ c++14

在 C++11 之前,我经常使用 boost::bindboost::lambda.bind 部分成为标准库(std::bind),另一部分成为核心语言(C++ lambdas)的一部分,并大量使用 lambdas更轻松.现在,我几乎不使用 std::bind,因为我几乎可以用 C++ lambda 做任何事情.我能想到的 std::bind 有一个有效的用例:

Before C++11 I used boost::bind or boost::lambda a lot. The bind part made it into the standard library (std::bind) the other part became part of the core language (C++ lambdas) and made the use of lambdas a lot easier. Nowadays, I hardly use std::bind, since I can do almost anything with C++ lambdas. There's one valid use-case for std::bind that I can think of:

struct foo
{
  template < typename A, typename B >
  void operator()(A a, B b)
  {
    cout << a << ' ' << b;
  }
};

auto f = bind(foo(), _1, _2);
f( "test", 1.2f ); // will print "test 1.2"

C++14 的等价物是

The C++14 equivalent for that would be

auto f = []( auto a, auto b ){ cout << a << ' ' << b; }
f( "test", 1.2f ); // will print "test 1.2"

更短更简洁.(在 C++11 中,由于自动参数,这还不起作用.)是否有任何其他有效的 std::bind 用例击败 C++ lambdas 替代方案,或者是 std::bind 用 C++14 是多余的吗?

Much shorter and more concise. (In C++11 this does not work yet because of the auto parameters.) Is there any other valid use case for std::bind beating the C++ lambdas alternative or is std::bind superfluous with C++14?

推荐答案

Scott Meyers 给出了一个 谈论关于这个.这是我记得的:

Scott Meyers gave a talk about this. This is what I remember:

在 C++14 中,没有什么有用的 bind 可以做而 lambdas 也做不到.

In C++14 there is nothing useful bind can do that can't also be done with lambdas.

在 C++11 中,但是有些事情不能用 lambda 来完成:

In C++11 however there are some things that can't be done with lambdas:

  1. 在创建 lambda 表达式时,您不能在捕获时移动变量.变量总是被捕获为左值.对于绑定,您可以编写:

  1. You can't move the variables while capturing when creating the lambdas. Variables are always captured as lvalues. For bind you can write:

auto f1 = std::bind(f, 42, _1, std::move(v));

  • 无法捕获表达式,只能捕获标识符.对于绑定,您可以编写:

  • Expressions can't be captured, only identifiers can. For bind you can write:

    auto f1 = std::bind(f, 42, _1, a + b);
    

  • 重载函数对象的参数.问题中已经提到了这一点.

  • Overloading arguments for function objects. This was already mentioned in the question.

    在 C++14 中,所有这些都是可能的.

    In C++14 all of these possible.

    1. 移动示例:

    1. Move example:

    auto f1 = [v = std::move(v)](auto arg) { f(42, arg, std::move(v)); };
    

  • 表达式示例:

  • Expression example:

    auto f1 = [sum = a + b](auto arg) { f(42, arg, sum); };
    

  • 查看问题

  • See question

    完美转发:可以写

    auto f1 = [=](auto&& arg) { f(42, std::forward<decltype(arg)>(arg)); };
    

  • 绑定的一些缺点:

    • 绑定按名称绑定,因此如果您有多个具有相同名称的函数(重载函数),则绑定不知道该使用哪个.下面的例子不会编译,而 lambdas 不会有问题:

    • Bind binds by name and as a result if you have multiple functions with the same name (overloaded functions) bind doesn't know which one to use. The following example won't compile, while lambdas wouldn't have a problem with it:

    void f(int); void f(char); auto f1 = std::bind(f, _1, 42);
    

  • 使用绑定函数时不太可能被内联
  • 另一方面,lambdas 理论上可能生成比绑定更多的模板代码.因为对于每个 lambda,您都会获得一个独特的类型.对于绑定来说,只有当你有不同的参数类型和不同的函数时(我猜在实践中,你用相同的参数和函数绑定多次的情况并不经常发生).

    On the other hand lambdas might theoretically generate more template code than bind. Since for each lambda you get a unique type. For bind it is only when you have different argument types and a different function (I guess that in practice however it doesn't happen very often that you bind several time with the same arguments and function).

    Jonathan Wakely 在他的回答中提到的实际上是不使用 bind 的另一个原因.我不明白你为什么要默默地忽略争论.

    What Jonathan Wakely mentioned in his answer is actually one more reason not to use bind. I can't see why you would want to silently ignore arguments.

    相关文章