C++11的std::bind是个巨大的进步,把各种稀奇古怪的函数对象统一起来。古老的bind1st终于退出历史舞台。但是bind仍旧存在漏洞。例如:
#include <iostream> #include <cmath> #include <functional> // std::bind using namespace std::placeholders; // adds visibility of _1, _2, _3,... double bevel(double a, double b){ std::cout << "bevel called" << std::endl; return std::sqrt(a*a+b*b); } double add(double a, double b){ std::cout << "add called" << std::endl; return a+b; } int main(){ auto fun = std::bind( bevel, add(1,2), _1 ); //一个callable fun(4); //调用fun,结果是5 }
调用std::bind函数时,需要对add(1,2)这个子表达式求值,如果想“延迟”求值,只能这么做:
1 #include <iostream> 2 #include<cmath> 3 #include <functional> // std::bind 4 using namespace std::placeholders; // adds visibility of _1, _2, _3,... 5 6 double bevel(double a, double b){ 7 std::cout << "bevel called" << std::endl; 8 return std::sqrt(a*a+b*b); 9 } 10 11 double add(double a, double b){ 12 std::cout << "add called" << std::endl; 13 return a+b; 14 } 15 16 int main() 17 { 18 auto fun = std::bind( bevel, std::bind(add,1,2), _1 ); 19 std::cout << "now fun call" << std::endl; 20 fun(4);21 }
第18行嵌套一个bind就把人搞晕。嵌套的bind(add,1,2)不会立刻调用add,只会返回一个callable对象,传递给外层的bind。
当调用第20行时,实际上就是调用了bevel( someCallableObj(), 4 ); someCallableObj()调用add(1,2),因此延迟调用实现。
C++14开始出现的lambda表达式,让明察的洞见穿透了这些隐晦的角落,改造后的代码如下:
//... as before int main() { auto funL = [](double b){ return bevel( add(1,2) , b ); }; std::cout << "now funL call\n"; funL(4); return 0; }
根据Effective Modern C++的作者之言,如果还看不到lambda表达式的好处,那简直和瞎子没什么两样。
下面再感受一下时代的变迁:
#include <functional> #include <algorithm> using namespace std; int main () { int numbers[] = {10,20,30,40,50,10}; int cx = count_if (numbers, numbers+6, bind1st(equal_to<int>(),10) ); }
C++03 要根据参数类型选函数bind1st(逆向思维,相当费脑)
#include <functional> #include <algorithm> using namespace std; using namespace std::placeholders; int main () { int numbers[] = {10,20,30,40,50,10}; int cx = count_if (numbers, numbers+6, bind(equal_to<int>(),10,_1) ); }
C++11 终于把函数先定下来就是一个std::bind, 然后选各项参数,callable对象,值参数,占位符参数。终于思维正常了。
#include <algorithm> using namespace std; int main () { int numbers[] = {10,20,30,40,50,10}; int cx = count_if (numbers, numbers+6, [](int i){ return i==0; } ); }
C++17 的lambda。不再需要什么_1,_2,_3。。。占位符能弄晕很多人。直白的代码逻辑。