在看C++标准程序库书中,看到bind1st,bind2nd及bind的用法,当时就有一种熟悉感,仔细想了下,是F#里提到的柯里化。下面是维基百科的解释:在计算机科学中,柯里化英语:Currying),又译为卡瑞化加里化,是把接受多个参数函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

  下面来看一个简单的例子。

  1. void mult(int& a, int b)
  2. {
  3. cout << "a:" << a << " b:" << b << endl;
  4. a += b;
  5. }
  6. void test24()
  7. {
  8. using namespace std::placeholders;
  9. vector<int> list;
  10. int i = ;
  11. generate_n(back_inserter(list), , [&i](){
  12. return i++;
  13. });
  14. for_each(list.begin(), list.end(), bind(mult, _1, ));
  15. for_each(list.begin(), list.end(), bind(mult, , _1));
  16. copy(list.begin(), list.end(), ostream_iterator<int>(cout, " "));
  17. }

bind用法

  

  在这,for_each最后接受一个void fun(int p)的函数做参数,p就是我们的每次遍历的数据,而在这我们用到mult,带有二个参数。在这我们就要用到柯里化,把mult转成前面的void fun(int p)的形式,下面我们看下相应函数如何工作。

  我们先来看下bind1st,这个相当于做了如下事。 f(a,b) -> f(a)(b).简单来说,就是把带二个参数的函数变成只带一个参数的函数的过程。bind2nd如上,类似f(a,b)->f(b)(a).而bind的用法更广,不限制个数,参数顺序和函数类型等。上面第一个for_each中bind的用法就相当于bind2nd,第二个就相当于bind1st.

  下面再来看个小例子:

  1. void test23()
  2. {
  3. using namespace std::placeholders;
  4. auto func = [](int x, string y){
  5. return to_string(x) + y;
  6. };
  7. auto f = bind(func, , _1);
  8. auto fs = bind(func, _1, "xx");
  9. auto fss = bind(func, , "xxx");
  10. auto fsss = bind(func, _2, _1);
  11.  
  12. cout << f("x") << endl;
  13. cout << fs() << endl;
  14. cout << fss() << endl;
  15. cout << fsss("xxxx", ) << endl;
  16. }

C++ bind

  输出结果分别是1x,2xx,3xxx,4xxxx.在二个参数的情况下,bind的几种简单重组函数的方法。为了好理解与说明,我直接把对应F#里相应写法写出。

  1. let func x y = x.ToString() + y
  2. let f x = func x
  3. let fs x = func x "xx"
  4. let fss = func "xxx"
  5. let fsss x y = func y x
  6.  
  7. [<EntryPoint>]
  8. let main argv =
  9. printfn "%s" (f "x")
  10. printfn "%s" (fs )
  11. printfn "%s" (fss)
  12. printfn "%s" (fsss "xxxx" )
  13.  
  14. ignore(System.Console.Read())
  15. // 返回整数退出代码

F# bind

  F#因为本身就是FP语言,故相应在C++还需要调用外部函数相比,本身内部支持。

  如下是对应各变量类型:

  val func : x:'a -> y:string -> string
  val f : x:string -> string
  val fs : x:'a -> string
  val fss : string = "3xxx"
  val fsss : x:string -> y:'a -> string

  在这,我们把泛形a具体化成int类型,好做说明,func (int,string)->string.而f是func第一参数具体化后生成的新的函数,fs是第二个参数具体化后生成新的函数,其中fss略过,而fsss则是把原(int,string)->string类型函数变成(string,int)->string的类型函数。

  如果F#难理解,下面是C#版的bind方法,只是简单针对二个参数的函数情况下,希望这个有助大家理解。

  1. public class BindHelper
  2. {
  3. public static Func<T1, T> bind<T1, T2, T>(Func<T1, T2, T> fun, T2 t2)
  4. {
  5. return (t11) =>
  6. {
  7. return fun(t11, t2);
  8. };
  9. }
  10.  
  11. public static Func<T2, T> bind<T1, T2, T>(Func<T1, T2, T> fun, T1 t1)
  12. {
  13. return (t22) =>
  14. {
  15. return fun(t1, t22);
  16. };
  17. }
  18.  
  19. public static Func<T> bind<T1, T2, T>(Func<T1, T2, T> fun, T1 t1, T2 t2)
  20. {
  21. return () =>
  22. {
  23. return fun(t1, t2);
  24. };
  25. }
  26.  
  27. public static Func<T2, T1, T> bind<T1, T2, T>(Func<T1, T2, T> fun)
  28. {
  29. return (t22, t11) =>
  30. {
  31. return fun(t11, t22);
  32. };
  33. }
  34.  
  35. static void Main()
  36. {
  37. Func<int, string, string> func = (int x, string y) => { return x.ToString() + y; };
  38. var f = bind(func, );
  39. var fs = bind(func, "xx");
  40. var fss = bind(func, , "xxx");
  41. var fsss = bind(func);
  42.  
  43. Console.WriteLine(f("x"));
  44. Console.WriteLine(fs());
  45. Console.WriteLine(fss());
  46. Console.WriteLine(fsss("xxxx", ));
  47. Console.Read();
  48. }
  49. }

C# bind

  这个应该是最好理解了,相应bind的重载方法在C#中列出如何实现。

  最后上文中float(*(*f)(float, float))(float)如何初始化还是没搞定,不过相应类似的可以正确初始化。也可以看下bind中带bind代表的方法与意义。

  1. //如何具体化.
  2. float(*(*f)(float, float))(float);
  3.  
  4. auto fvv = function<function<float(float)>(float, float)>(f);
  5.  
  6. auto fv = [](float f, float d){
  7. return[](float c)
  8. {
  9. return c;
  10. };
  11. };
  12.  
  13. using namespace std::placeholders;
  14. fvv = fv;
  15. //f = fv;
  16. auto x = bind(bind(fv, _1, _1)(), _1)();
  17. auto xxx = fv(, )(2.0f);
  18. auto yyy = fvv(, )(2.0f);
  19. cout << x << endl;

  PS:STL刚开始看,只能说C++的模板与泛形太强大了,相应模板方法可以用动态语言的方式写(声明有这元素,这元素能做啥,就和javascript一样),而编译时,根据调用相应模板方法得到正确的具体化方法就相当于运行结果。所以很多模板调用错误是在编译阶段指出来的。

  

C++标准 bind函数用法与C#简单实现的更多相关文章

  1. c/c++ 标准库 bind 函数 详解

    标准库 bind 函数 详解 bind函数:接收一个函数名作为参数,生成一个新的函数. auto newCallable = bind(callbale, arg_list); arg_list中的参 ...

  2. 博文推荐】Javascript中bind、call、apply函数用法

    [博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...

  3. JavaScript中bind、call、apply函数用法详解

    在给我们项目组的其他程序介绍 js 的时候,我准备了很多的内容,但看起来效果不大,果然光讲还是不行的,必须动手.前几天有人问我关于代码里 call() 函数的用法,我让他去看书,这里推荐用js 写服务 ...

  4. Javascript中bind、call、apply函数用法

    js 里函数调用有 4 种模式:方法调用.正常函数调用.构造器函数调用.apply/call 调用. 同时,无论哪种函数调用除了你声明时定义的形参外,还会自动添加 2 个形参,分别是 this 和ar ...

  5. 标准库bind函数中使用占位符placeholders

    placeholders ,占位符.表示新的函数对象中参数的位置.当调用新的函数对象时,新函数对象会调用被调用函数,并且其参数会传递到被调用函数参数列表中持有与新函数对象中位置对应的占位符. 举个例子 ...

  6. apply,call,bind函数作用与用法

    作用 可以把方法借给其它对象使用,并且改变this的指向 a.apply(b,[3,2]);//this指向由a变为b, a的方法借给b使用 实例: function add(a,b){       ...

  7. C++11 标准库 bind 函数

    bind 是什么? bind 顾名思义: 绑定 通俗来讲呢,可以这么理解有点像函数指针的意思. 资料上是这么讲的:可以将 bind 函数看做一个通用函数的适配器,它接受一个可调用对象,生成一个新的可以 ...

  8. Perl Sort函数用法总结和使用实例

    一) sort函数用法 sort LISTsort BLOCK LISTsort SUBNAME LIST sort的用法有如上3种形式.它对LIST进行排序,并返回排序后的列表.假如忽略了SUBNA ...

  9. call,apply,bind函数

    一.call函数 a.call(b); 简单的理解:把a对象的方法应用到b对象上(a里如果有this,会指向b) call()的用法:用在函数上面 var Dog=function(){ this.n ...

随机推荐

  1. nginx 环境下http和https(ssl)共存的方法

    80 443喘口共存之前是没问题的,但这次突然发现了这样的问题,htpps可以访问,但http不能访问会反回400 1xx.6x.x9.x8 - - [19/Jun/2017:16:04:28 +08 ...

  2. 菜鸟学Java(十八)——异常

    每个学编程的人在编程的过程中都会遇到各种异常.那么当我们遇到异常的时候该怎么处理呢?针对不同的异常我们又该采取什么具体的处理方式呢?这些问题在我开始学编程的很长一段时间里我都不太清楚,还好随着不断的学 ...

  3. Android Dialog-Dialog无法充满横屏且下方有间隔

    自定义一个Dialog,写完布局后运行,发现Dialog无法充满屏幕,就像下边这样: 代码大致如下: Dialog dialog = new Dialog(this); dialog.requestW ...

  4. 关于CAE的那点儿破事儿

    CAE是计算机辅助工程的英文简写,所涵盖的范围甚是广泛.现在很多人提到CAE,总是联想到结构有限元计算,更有甚者认为有限元就是CAE.还有人把所有的工程数值计算都称作有限元.本文就这一话题,来谈谈关于 ...

  5. lua -- io.pathinfo

    io.pathinfo 拆分一个路径字符串,返回组成路径的各个部分. 格式: parts = io.pathinfo(路径) 使用示例: local pathinfo = io.pathinfo(&q ...

  6. MVC+EF+PagedList+调用通用存储封装+多表联合信息展示分页+存储过程分页

    主要的技术点不在这里一一阐述,相关存储也是引用别人的,主要技术点就是通过最优性能方式处理需求,PagedList.包需要在线安装就可以 直接上干货 1.存储代码之第一种: 参数相对多点 /**//* ...

  7. MVC的项目部署成应用程序或虚拟目录路径的问题

    1.js和css的引用出错 a.~/可以取得应用程序目录 b. ./定位到路径,./代表到本目录,../代表父级目录 2.打开页面view a. ./定位到路径 3.img src   a. ./定位 ...

  8. [转载]Lua和C++交互详细总结

    原文请看:Lua和C++交互详细总结 转自:http://cn.cocos2d-x.org/tutorial/show?id=1474 一.Lua堆栈 要理解Lua和C++交互,首先要理解Lua堆栈. ...

  9. 设置模式之单例模式(附上一个Objective-C编写的播放音乐的单例类)

    在查阅Cocoa Touch开发文档时,会发现框架中随处可见的大量单例类,比如说,UIApplication.NSFileManager 等. UIApplication 框架中极为常用的一个单例类, ...

  10. spacemacs怎样配置编辑器显示行号?

    spacemacs配置文件.spacemacs文件中查找dotspacemacs-line-numbers. 默认配置为: dotspacemacs-line-numbers nil 修改为(`rel ...