FireEmissary

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  14 随笔 :: 0 文章 :: 20 评论 :: 0 Trackbacks
老实说,我不知道C++11有了lambda,怎么还会要引入bind.
bind这玩意,嵌套两层就得出汗,嵌套三四层绝对要人提心吊胆验证n久.还有个自以为是的功能:如果绑定的参数是bind对象,它就自作聪明去调用.问题是,有时候你确实要个可调用对象而不是可调用对象的调用返回值,你要不就得用ref包裹bind,要不就得格外写个可调用对象使得std::is_bind_expression<T>::value == true判断不成立.这格外写个可调用对象的简单方法是什么:就是用lambda.....
有人会说:bind能做的事lambda不能做,比如bind可以绑定一个可调用对象,这个可调用对象有多个可调用operator call或者template call.如下:

 struct foo
{
typedef 
void result_type;

template 
< typename A, typename B >
void operator()(A a, B b)
{
std::cout 
<< "operator()(A a, B b)"<<std::endl;
}
void operator()(int a,int b)
{
std::cout 
<< "operator()(int a,int b)"<<std::endl;
}
int operator()(int a,char b)
{
std::cout 
<< "operator()(int a,char b)"<<std::endl;
return 1;
}
};
int main()
{
using namespace std::placeholders;
auto f 
= std::bind(foo(), _1,_2);
f(
"test"1.2f);
f(
2,3);
std::cout
<<"get:"<<f(2,'3');
return 0;
}

没错,lambda必须指定函数参数类型,表面上看也许没那么"可变".然而你要考虑实际应用场景.bind一个对象后怎么用它呢?一般使用场景是保存起来以备使用.而目前class 成员显然不是一个auto可以指定,它得是具体的类型,比如std::function<void(int ,float)>.如果把上面代码里的 f保存在一个std::function<void(int ,float)>类型里面,那么当后来调用它传入两个整型时会调用哪个函数?不是operator()(int a,int b)  而是operator()(A a, B b)!所以除非你bind一个对象后立马在当前函数里使用(多此一举),否则bind的参数灵活性基本发挥不出来.
这就给出了两个易出错场景:
一个是传给bind的参数是可调用对象是,表现不一样(可调用对象是另一个bind时,会被调用,其它则当成普通对象)
另一个是对于bind一个类,类里面有多个可调用函数时,出现你以为调用operator()(int a,int b)  而实际上是operator()(A a, B b).反之lambda的直观使得它更容易找出问题.
再加上bind多层嵌套使用带来的可读性问题(这其实也是易出错场景),我的看法是:学好lambda,远离bind.
posted on 2013-03-10 09:11 FireEmissary 阅读(7936) 评论(11)  编辑 收藏 引用

评论

# re: 使用lambda,远离bind 2013-03-11 00:57 YzL
auto是C++11才有的东西,而bind()已经存在并在旧的C++标准上实现了很久了,比如boost::bind(),并不是只有auto才能保存/推导bind()对象,模版也可以,看下面的代码:
template<typename CallType>
void Func(CallType call)
{
call();
}
这种情况bind()能生成/适配出实际上具有N个参数的call(),lambda则永远只能没参数,虽然lambda可以访问外部变量来模拟多参数,但是当Func()需要多次在不同的作用域调用、或者call()本身是第三方库时,bind()就要方便得多  回复  更多评论
  

# re: 使用lambda,远离bind[未登录] 2013-03-11 03:43 lost
求排版  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-12 15:26 w
还是传统的写法简单靠谱, 非得搞这些所谓的乱七八糟的新特性,c++真是走火入魔了  回复  更多评论
  

# re: 使用lambda,远离bind[未登录] 2013-03-14 00:05 Jcily
我觉得bind和lambda这两个面向的问题针对性不同。

两者并没有可比性。

bind体现在帮助我们简洁快速的打包一个函数对象的便捷性,而不用像“仿函数”去手动用操作符重载的方法写一个class或者struct。

lambda重点是当你需要一个闭包。比如你懒得去定义一个只会被这里调用一次的回调函数,更不想另外手写定义一些变量帮它保存当时的局部环境状态。  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-14 09:50 xinqing
lambda可以有参数,也可以有返回值  回复  更多评论
  

# re: 使用lambda,远离bind[未登录] 2013-03-14 13:25
@Jcily
顶  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-15 16:10 bill gates
bind有个东西叫protect,就是用来取消函数组合(bind的默认行为)。C++最大的问题是用底层概念实现了上层抽象,这样在调试程序的时候,由于底层实现不是自己写的,导致出问题几乎无法调试,除非你去看那些实现的源代码。调试过几次bind,相当痛苦。  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-15 16:11 liyou
@Jcily
有见地。  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-15 22:54 wingfire
“除非你bind一个对象后立马在当前函数里使用(多此一举),否则bind的参数灵活性基本发挥不出来.”
这个何出此言?不考虑和模板的合作吗?bind的结果可以传给模板函数啊,不一定要返回。就算返回,在类型自动推导时也是有用的。  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-15 22:55 wingfire
lambda不支持模板是C++11的一大败笔,事实就是如此。  回复  更多评论
  

# re: 使用lambda,远离bind 2013-03-16 13:35 FireEmissary
@wingfire
lambda不支持模板是遗憾而不是败笔,因为它并非将来不可改进.
至于和模板的合作,从最新的书籍来看也是建议用lambda.诚如<<The C++ Standard Library>>Second Edition所说(10.2.4):


std::find_if (coll.begin(), coll.end(),
std::bind(std::logical_not<bool>(),
std::bind(std::modulus<int>(),
std::placeholder::_1,
2)));

Being able to use a lambda is really an improvement here:

std::find_if (coll.begin(), coll.end(),
[](int elem){
return elem%2==0;
});
  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理