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

时间:2012-08-21 20:38:44

标签: c++ lambda c++11 boost-lambda boost-phoenix

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

使用例如boost::lambda(或boost::phoenix)与C ++ 11风格的lambda相比有什么实际优势?

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

3 个答案:

答案 0 :(得分: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
}

答案 1 :(得分: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);
}

答案 2 :(得分:3)

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

如果你的lambda在 任何 方式上彼此不同,它们将生成不同的代码,编译器可能无法合并相同的部分。 (内联使得这更加困难。)

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

这会不成比例地破坏代码大小。

然而,

bind通常对这些变化更具弹性(尽管不能免疫它们)。

说明我的意思......

  1. 以下面的示例,使用GCC(或Visual C ++)编译它,并记下输出二进制文件大小。
  2. 尝试将if (false)更改为if (true),并查看输出二进制文件大小的变化。
  3. 在评论除了每个部分中的stable_sort之外的所有之后重复#1和#2。
  4. 请注意,第一个时间,C ++ 11 lambdas略小;之后,每次使用后它们的大小都会爆炸(每个类型使用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; });
        }
    }
    

    请注意,这是“交易速度”;如果你在非常非常 紧密循环中,它可能涉及一个额外的变量(因为现在它使用指向成员的指针)。
    但是,这是 nothing ,如开销std::function引入的(这是一个虚拟调用),而甚至在许多情况下都是无法测量的,所以这不应该值得关注。