博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++标准 bind函数用法与C#简单实现
阅读量:5923 次
发布时间:2019-06-19

本文共 3851 字,大约阅读时间需要 12 分钟。

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

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

void mult(int& a, int b){    cout << "a:" << a << " b:" << b << endl;    a += b;}void test24(){    using namespace std::placeholders;    vector
list; int i = 0; generate_n(back_inserter(list), 10, [&i](){ return i++; }); for_each(list.begin(), list.end(), bind(mult, _1, 10)); for_each(list.begin(), list.end(), bind(mult, 100, _1)); copy(list.begin(), list.end(), ostream_iterator
(cout, " "));}
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.

  下面再来看个小例子:

void test23(){    using namespace std::placeholders;    auto func = [](int x, string y){        return to_string(x) + y;    };    auto f = bind(func, 1, _1);    auto fs = bind(func, _1, "xx");    auto fss = bind(func, 3, "xxx");    auto fsss = bind(func, _2, _1);    cout << f("x") << endl;    cout << fs(2) << endl;    cout << fss() << endl;    cout << fsss("xxxx", 4) << endl;}
C++ bind

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

let func x y = x.ToString() + ylet f x = func 1 xlet fs x = func x "xx"let fss = func 3 "xxx"let fsss x y = func y x[
]let main argv = printfn "%s" (f "x") printfn "%s" (fs 2) printfn "%s" (fss) printfn "%s" (fsss "xxxx" 4) ignore(System.Console.Read()) 0 // 返回整数退出代码
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方法,只是简单针对二个参数的函数情况下,希望这个有助大家理解。

public class BindHelper    {        public static Func
bind
(Func
fun, T2 t2) { return (t11) => { return fun(t11, t2); }; } public static Func
bind
(Func
fun, T1 t1) { return (t22) => { return fun(t1, t22); }; } public static Func
bind
(Func
fun, T1 t1, T2 t2) { return () => { return fun(t1, t2); }; } public static Func
bind
(Func
fun) { return (t22, t11) => { return fun(t11, t22); }; } static void Main() { Func
func = (int x, string y) => { return x.ToString() + y; }; var f = bind(func, 1); var fs = bind(func, "xx"); var fss = bind(func, 3, "xxx"); var fsss = bind(func); Console.WriteLine(f("x")); Console.WriteLine(fs(2)); Console.WriteLine(fss()); Console.WriteLine(fsss("xxxx", 4)); Console.Read(); } }
C# bind

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

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

//如何具体化.    float(*(*f)(float, float))(float);    auto fvv = function
(float, float)>(f); auto fv = [](float f, float d){ return[](float c) { return c; }; }; using namespace std::placeholders; fvv = fv; //f = fv; auto x = bind(bind(fv, _1, _1)(4), _1)(6); auto xxx = fv(3, 4)(2.0f); auto yyy = fvv(3, 4)(2.0f); cout << x << endl;
View Code

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

  

转载地址:http://gqxvx.baihongyu.com/

你可能感兴趣的文章
Veeam产品战略副总裁兼首席宣传大使Doug Hazelman通过回顾过去十年的变化,预测未来十年的科技世界将会如何发展...
查看>>
ODCC开放数据中心峰会即将召开 十道“技术大餐”提前揭秘
查看>>
Jerry眼中的SAP客户数据模型
查看>>
FBS2017独家观察:食品饮料CIO的心声 你听到了吗?
查看>>
阿里云如何打破Oracle迁移上云的壁垒
查看>>
好好的机器人,怎么就暴走了?
查看>>
日本研发双足行走机器人,奔跑速度堪比一流马拉松选手
查看>>
复杂性思维中文第二版 十一、进化
查看>>
SQL Server数据同步的研究(单向/双向)
查看>>
阿里健康宣布 106 亿港元收购天猫医疗器械、保健用品等业务
查看>>
不同的应用场景AGV导航方式分析
查看>>
JDK居然还有Server和Client模式
查看>>
定制Eclipse IDE之插件篇(二)
查看>>
MyFlash MySQL闪回工具
查看>>
一个简单的四则运算
查看>>
2017中国互联网大会正在召开
查看>>
如何取消或定制当点击GridView 的时候出现的那个黄色背景
查看>>
算年龄
查看>>
SpringMVC解析1-使用示例
查看>>
在Mac pro上如何配置adb命令?
查看>>