我有一个关于哪种样式是首选的问题:std :: bind Vs lambda in C ++ 0x。我知道它们服务于某些不同的目的,但我们举一个交叉功能的例子。
使用lambda
:
uniform_int<> distribution(1, 6);
mt19937 engine;
// lambda style
auto dice = [&]() { return distribution(engine); };
使用bind
:
uniform_int<> distribution(1, 6);
mt19937 engine;
// bind style
auto dice = bind(distribution, engine);
我们应该选择哪一个?为什么?假设与上述示例相比情况更复杂。即一个优于另一个的优点/缺点是什么?
答案 0 :(得分:43)
C ++ 0x lambdas是单态的,而bind可以是多态的。你不能拥有像
这样的东西auto f = [](auto a, auto b) { cout << a << ' ' << b; }
f("test", 1.2f);
a和b必须具有已知类型。另一方面,tr1 / boost / phoenix / lambda bind允许你这样做:
struct foo
{
typedef void result_type;
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"
请注意,此处的类型A和B 不已修复。只有当f实际使用时才会推导出这两个。
答案 1 :(得分:26)
正如你所说,bind和lambdas并不完全瞄准同一个目标。
例如,对于使用和编写STL算法,lambda是明显的赢家,恕我直言。
为了说明,我记得一个非常有趣的答案,这里有堆栈溢出,有人问十六进制魔数的想法,(如0xDEADBEEF,0xCAFEBABE,0xDEADDEAD等)并被告知如果他是一个真正的C ++程序员他只需下载一个英文单词列表,并使用简单的C ++单行代码:)
#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
int main()
{
using namespace boost::lambda;
std::ifstream ifs("wordsEn.txt");
std::remove_copy_if(
std::istream_iterator<std::string>(ifs),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"),
bind(&std::string::size, _1) != 8u
||
bind(
static_cast<std::string::size_type (std::string::*)(const char*, std::string::size_type) const>(
&std::string::find_first_not_of
),
_1,
"abcdef",
0u
) != std::string::npos
);
}
这个片段,在纯C ++ 98中,打开英文单词文件,扫描每个单词,只打印长度为8的单词“a”,“b”,“c”,“d”,“e”或'f'字母。
现在,打开C ++ 0X和lambda:
#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
int main()
{
std::ifstream ifs("wordsEn.txt");
std::copy_if(
std::istream_iterator<std::string>(ifs),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[](const std::string& s)
{
return (s.size() == 8 &&
s.find_first_not_of("abcdef") == std::string::npos);
}
);
}
这仍然有点沉重(主要是因为istream_iterator业务),但比绑定版本简单得多:)
答案 2 :(得分:18)
C ++ 0x lamdba语法比绑定语法更具可读性。一旦你进入超过2-3级绑定,你的代码变得非常难以理解并且难以维护。我更喜欢更直观的lambda语法。
答案 3 :(得分:8)
lambdas的一个好处是,当你需要在现有函数之上添加一点逻辑时,它们会更有用。
使用bind,即使只在这一个地方需要逻辑,你也不得不创建一个新的函数/方法/仿函数。您需要提供一个合适的名称,它可以使代码不易理解,因为它可能会使您分离相关的逻辑。
使用lambda,你可以在lambda中添加新的逻辑(但是如果创建一个新的callable是有意义的话,不会被强制使用。)
答案 4 :(得分:3)
我认为这更属于品味问题。快速掌握新技术或熟悉函数式编程的人可能更喜欢lambda语法,而更保守的程序员肯定更喜欢bind,因为它更符合传统的C ++语法。
这样的决定应该与将要使用代码的人协调,可能通过多数投票。
然而,这并没有改变这一事实,即lambda语法更强大,更清晰。
答案 5 :(得分:1)
C ++ 0x lambdas基本上取代了bind。你无法绑定任何东西,你无法重新创建一个简单的包装lambda来实现相同的目标。一旦lambda支持广泛传播,std :: tr1 :: bind将采用std :: bind1st等方式。哪个好,因为出于某种原因,大多数程序员都很难理解绑定。
答案 6 :(得分:0)
lambdas的主要优点是它们可以静态引用成员函数,而bind只能通过指针引用它们。更糟糕的是,至少在遵循“ itanium c ++ ABI”的编译器(例如g ++和clang ++)中,指向成员函数的指针的大小是普通指针的两倍。
因此,至少对于g ++,如果执行类似std::bind(&Thing::function, this)
的操作,则得到的结果是大小为三个指针,两个为成员函数指针,一个为this指针。另一方面,如果您执行[this](){function()}
,则结果将只有一个指针大小。
std :: function的g ++实现最多可以存储两个指针,而无需动态分配内存。因此,将成员函数绑定到此函数并将其存储在std :: function中将导致动态内存分配,而使用lambda却不会捕获到该函数。