我正在考虑将我的代码迁移到使用 C++11 风格的 lambda,而不是bind
到处都有 s 。但我不确定这是否是个好主意。
与 C++11 风格的 lambda 相比,使用 eg boost::lambda
(or boost::phoenix
) 有什么实际优势吗?
转移到 lambdas 是个好主意吗?我是否应该迁移我的代码?
我正在考虑将我的代码迁移到使用 C++11 风格的 lambda,而不是bind
到处都有 s 。但我不确定这是否是个好主意。
与 C++11 风格的 lambda 相比,使用 eg boost::lambda
(or boost::phoenix
) 有什么实际优势吗?
转移到 lambdas 是个好主意吗?我是否应该迁移我的代码?
主要优点是多态函子。目前,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
}
是的,Boost lambdas 是多态的,C++11 lambdas 不是。这意味着,例如,您不能使用 C++11 lambda 来做到这一点:
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);
}
如果您的 lambdas 以任何方式彼此不同,它们将生成不同的代码,并且编译器可能无法合并相同的部分。(内联使这变得更加困难。)
当你第一次看到它时,这看起来没什么大不了的,直到你注意到:
当你在模板函数中使用它们时std::sort
,编译器会为每个不同的 lambda生成新代码。
这可能会不成比例地增加代码大小。
bind
但是,它通常对此类更改更具弹性(尽管不能对它们免疫)。
为了说明我的意思...
if (false)
为if (true)
,并查看输出二进制大小如何更改。stable_sort
s之外的所有内容后重复 #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; });
}
}
请注意,这是“以交易规模换取速度”;如果你处于一个非常紧凑的循环中,它可能涉及一个额外的变量(因为现在它使用指向成员的指针)。
但是,这与引入的开销std::function
(这是一个虚拟调用)完全不同,即使在许多情况下也是无法测量的,因此这不应该引起关注。