C++标准 bind函数用法与C#简单实现
在看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<int> list;
int i = ;
generate_n(back_inserter(list), , [&i](){
return i++;
});
for_each(list.begin(), list.end(), bind(mult, _1, ));
for_each(list.begin(), list.end(), bind(mult, , _1));
copy(list.begin(), list.end(), ostream_iterator<int>(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);
auto fs = bind(func, _1, "xx");
auto fss = bind(func, , "xxx");
auto fsss = bind(func, _2, _1); cout << f("x") << endl;
cout << fs() << endl;
cout << fss() << endl;
cout << fsss("xxxx", ) << endl;
}
C++ bind
输出结果分别是1x,2xx,3xxx,4xxxx.在二个参数的情况下,bind的几种简单重组函数的方法。为了好理解与说明,我直接把对应F#里相应写法写出。
let func x y = x.ToString() + y
let f x = func x
let fs x = func x "xx"
let fss = func "xxx"
let fsss x y = func y x [<EntryPoint>]
let main argv =
printfn "%s" (f "x")
printfn "%s" (fs )
printfn "%s" (fss)
printfn "%s" (fsss "xxxx" ) ignore(System.Console.Read())
// 返回整数退出代码
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<T1, T> bind<T1, T2, T>(Func<T1, T2, T> fun, T2 t2)
{
return (t11) =>
{
return fun(t11, t2);
};
} public static Func<T2, T> bind<T1, T2, T>(Func<T1, T2, T> fun, T1 t1)
{
return (t22) =>
{
return fun(t1, t22);
};
} public static Func<T> bind<T1, T2, T>(Func<T1, T2, T> fun, T1 t1, T2 t2)
{
return () =>
{
return fun(t1, t2);
};
} public static Func<T2, T1, T> bind<T1, T2, T>(Func<T1, T2, T> fun)
{
return (t22, t11) =>
{
return fun(t11, t22);
};
} static void Main()
{
Func<int, string, string> func = (int x, string y) => { return x.ToString() + y; };
var f = bind(func, );
var fs = bind(func, "xx");
var fss = bind(func, , "xxx");
var fsss = bind(func); Console.WriteLine(f("x"));
Console.WriteLine(fs());
Console.WriteLine(fss());
Console.WriteLine(fsss("xxxx", ));
Console.Read();
}
}
C# bind
这个应该是最好理解了,相应bind的重载方法在C#中列出如何实现。
最后上文中float(*(*f)(float, float))(float)如何初始化还是没搞定,不过相应类似的可以正确初始化。也可以看下bind中带bind代表的方法与意义。
//如何具体化.
float(*(*f)(float, float))(float); auto fvv = function<function<float(float)>(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)(), _1)();
auto xxx = fv(, )(2.0f);
auto yyy = fvv(, )(2.0f);
cout << x << endl;
PS:STL刚开始看,只能说C++的模板与泛形太强大了,相应模板方法可以用动态语言的方式写(声明有这元素,这元素能做啥,就和javascript一样),而编译时,根据调用相应模板方法得到正确的具体化方法就相当于运行结果。所以很多模板调用错误是在编译阶段指出来的。
C++标准 bind函数用法与C#简单实现的更多相关文章
- c/c++ 标准库 bind 函数 详解
标准库 bind 函数 详解 bind函数:接收一个函数名作为参数,生成一个新的函数. auto newCallable = bind(callbale, arg_list); arg_list中的参 ...
- 博文推荐】Javascript中bind、call、apply函数用法
[博文推荐]Javascript中bind.call.apply函数用法 2015-03-02 09:22 菜鸟浮出水 51CTO博客 字号:T | T 最近一直在用 js 写游戏服务器,我也接触 j ...
- JavaScript中bind、call、apply函数用法详解
在给我们项目组的其他程序介绍 js 的时候,我准备了很多的内容,但看起来效果不大,果然光讲还是不行的,必须动手.前几天有人问我关于代码里 call() 函数的用法,我让他去看书,这里推荐用js 写服务 ...
- Javascript中bind、call、apply函数用法
js 里函数调用有 4 种模式:方法调用.正常函数调用.构造器函数调用.apply/call 调用. 同时,无论哪种函数调用除了你声明时定义的形参外,还会自动添加 2 个形参,分别是 this 和ar ...
- 标准库bind函数中使用占位符placeholders
placeholders ,占位符.表示新的函数对象中参数的位置.当调用新的函数对象时,新函数对象会调用被调用函数,并且其参数会传递到被调用函数参数列表中持有与新函数对象中位置对应的占位符. 举个例子 ...
- apply,call,bind函数作用与用法
作用 可以把方法借给其它对象使用,并且改变this的指向 a.apply(b,[3,2]);//this指向由a变为b, a的方法借给b使用 实例: function add(a,b){ ...
- C++11 标准库 bind 函数
bind 是什么? bind 顾名思义: 绑定 通俗来讲呢,可以这么理解有点像函数指针的意思. 资料上是这么讲的:可以将 bind 函数看做一个通用函数的适配器,它接受一个可调用对象,生成一个新的可以 ...
- Perl Sort函数用法总结和使用实例
一) sort函数用法 sort LISTsort BLOCK LISTsort SUBNAME LIST sort的用法有如上3种形式.它对LIST进行排序,并返回排序后的列表.假如忽略了SUBNA ...
- call,apply,bind函数
一.call函数 a.call(b); 简单的理解:把a对象的方法应用到b对象上(a里如果有this,会指向b) call()的用法:用在函数上面 var Dog=function(){ this.n ...
随机推荐
- create-react-app 使用详解
快速开始 npm install -g create-react-app create-react-app my-app cd my-app/ npm start 通过http://localhost ...
- 菜鸟学Java(十二)——搭建一个完整的Java开发环境
作为一个Java程序员,配置一个java开发环境是必备的技能,今天给广大菜鸟初学者补上一课.环境的配置,大概就分三个1,JDK 2,Tomcat(或者其他的)3,eclipse(或者myeclipse ...
- CCShatteredTiles3D
CCSprite* pImgBg = CCSprite::create("1.png"); pImgBg->setPosition(ccp(CCDirector::share ...
- Spark Streaming的接收KAFKA的数据
https://github.com/lw-lin/CoolplaySpark/blob/master/Spark%20Streaming%20%E6%BA%90%E7%A0%81%E8%A7%A3% ...
- Redis source code analysis
http://zhangtielei.com/posts/blog-redis-dict.html http://zhangtielei.com/assets/photos_redis/redis_d ...
- HTTPS演变小图
HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全.为了保证这些隐私数据能加密传输,网景公司设计了SSL(Se ...
- [AWS vs Azure] 云计算里AWS和Azure的探究(5) ——EC2和Azure VM磁盘性能分析
云计算里AWS和Azure的探究(5) ——EC2和Azure VM磁盘性能分析 在虚拟机创建完成之后,CPU和内存的配置等等基本上是一目了然的.如果不考虑显卡性能,一台机器最重要的性能瓶颈就是硬盘. ...
- 【ARM】2410裸机系列-按键查询式控制led
开发环境 硬件平台:FS2410 主机:Ubuntu 12.04 LTS LED灯原理图 按键原理图 按键的接线资源 KSCAN0 -> GPE11 KSCAN1 -> GPG6 ...
- Chrome中使用flash引起cpu飙升问题的处理
本人使用的是Chrome 30 flash 18,在看视频或者登陆有调用flash插件的页面之后,经常会遇到Shockwave Flash插件CPU占用超过50%的情况(在Chrome的任务管理器可以 ...
- [转]hive中自定义函数(UDAF)实现多行字符串拼接为一行
函数如何使用: hive> desc concat_test;OKa intb string hive> select * from concat_test;OK1 ...