设为首页 加入收藏

TOP

C++标准 bind函数用法与C#简单实现(一)
2015-07-20 17:17:41 来源: 作者: 【 】 浏览:7
Tags:标准 bind 函数 用法 简单 实现
在看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, " "));
}
?
  
?
  在这,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;
}
?
  输出结果分别是1x,2xx,3xxx,4xxxx.在二个参数的情况下,bind的几种简单重组函数的方法。为了好理解与说明,我直接把对应F#里相应写法写出。
?
?
?
let func x y = x.ToString() + y
let f x = func 1 x
let 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#因为本身就是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();
? ? ? ? }
? ? }
?
  这个应该是最好理解了,相应bind的重载
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇poj1740 A New Stone Game(博弈) 下一篇HDU 3068 最长回文 (Manacher算法)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·如何理解c语言指针和 (2025-12-27 01:19:11)
·为什么C标准库没有链 (2025-12-27 01:19:08)
·玩转C语言和数据结构 (2025-12-27 01:19:05)
·MySQL 基础入门视频 (2025-12-26 23:20:22)
·小白入门:MySQL超详 (2025-12-26 23:20:19)