bind()与C++ 11 lambdas相比有什么优势(兼容性除外)?

Meh*_*dad 14 c++ lambda boost-lambda boost-phoenix c++11

我正在考虑将我的代码迁移到使用C++ 11风格的lambda而不是bind到处都有.但我不确定这是不是一个好主意.

使用eg boost::lambda(或boost::phoenix)是否比C++ 11风格的lambdas有任何实际优势?

搬到lambdas是个好主意吗?我应该迁移我的代码吗?

Xeo*_*Xeo 10

主要优点是多态仿函数.目前,C++ 11 lambdas是单态的,即它们只采用单个参数类型,而bind()允许您创建接受任何参数类型的函子,只要绑定函子可以用它调用即可.

#include <functional>

struct X{
  template<class T, class U>
  void operator()(T, U) const{}
};

int main(){
  X x;
  auto l_with_5 = [x](int v){ return x(v, 5); };
  auto b_with_5 = std::bind(x, std::placeholders::_1, 5);
  l(4);
  b("hi"); // can't do that with C++11 lambdas
}
Run Code Online (Sandbox Code Playgroud)


ybu*_*ill 7

是的,Boost lambdas是多态的,C++ 11 lambda不是.这意味着,例如,你不能用C++ 11 lambdas做到这一点:

template<class T>
void f(T g)
{
    int x = 123;
    const char* y = "hello";
    g(x); // call with an integer
    g(y); // call with a string
}

int main() {
    f(std::cout << _1);
}
Run Code Online (Sandbox Code Playgroud)


Meh*_*dad 3

是的:它(有时)会显着影响输出大小。

如果您的 lambda 彼此之间有任何不同它们将生成不同的代码,并且编译器可能无法合并相同的部分。(内联使这变得更加困难。)

当您第一次看到它时,这看起来没什么大不了的,直到您注意到:
当您在模板化函数(如 )中使用它们时std::sort,编译器会每个不同的 lambda生成新代码。

这可能会不成比例地增加代码大小。

bind然而,通常对此类变化更具弹性(尽管不能幸免)。

为了说明我的意思...

  1. 以下面的示例为例,使用 GCC(或 Visual C++)对其进行编译,并记下输出的二进制大小。
  2. 尝试更改if (false)if (true),并查看输出二进制大小如何变化。
  3. 注释掉每个部分中除其中一个之外的所有stable_sort内容后,重复 #1 和 #2 。

请注意,第一次,C++11 lambda 稍微小一些;之后,它们的大小在每次使用后都会增大(使用 VC++ 时,每次排序大约需要 3.3 KB 代码,与 GCC 类似),而基于 - 的二进制文件几乎没有改变它们的大小(当所有四个都使用boost::lambda时,它对我来说保持相同的大小)包括在内,精确到半千字节)。

#include <algorithm>
#include <string>
#include <vector>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>   // can also use boost::phoenix

using namespace boost::lambda;

struct Foo { std::string w, x, y, z; };

int main()
{
    std::vector<Foo> v1;
    std::vector<size_t> v2;
    for (size_t j = 0; j < 5; j++) { v1.push_back(Foo()); }
    for (size_t j = 0; j < v1.size(); j++) { v2.push_back(j); }
    if (true)
    {
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::w, var(v1)[_1]) < bind(&Foo::w, var(v1)[_2]));
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::x, var(v1)[_1]) < bind(&Foo::x, var(v1)[_2]));
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::y, var(v1)[_1]) < bind(&Foo::y, var(v1)[_2]));
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::z, var(v1)[_1]) < bind(&Foo::z, var(v1)[_2]));
    }
    else
    {
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].w < v1[j].w; });
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].x < v1[j].x; });
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].y < v1[j].y; });
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].z < v1[j].z; });
    }
}
Run Code Online (Sandbox Code Playgroud)

注意,这是“以规模换速度”;如果你处于一个非常非常紧密的循环中,它可能会涉及一个额外的变量(因为现在它使用指向成员的指针)。
然而,这与引入的开销(这是虚拟调用)完全不同,甚至在许多情况下也是无法测量的,因此这不应该引起关注。std::function