程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++標准 bind函數用法與C#簡單實現

C++標准 bind函數用法與C#簡單實現

編輯:關於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 = 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<int>(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   [<EntryPoint>] 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<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, 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的重載方法在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)(4), _1)(6);     auto xxx = fv(3, 4)(2.0f);     auto yyy = fvv(3, 4)(2.0f);     cout << x << endl;     PS:STL剛開始看,只能說C++的模板與泛形太強大了,相應模板方法可以用動態語言的方式寫(聲明有這元素,這元素能做啥,就和javascript一樣),而編譯時,根據調用相應模板方法得到正確的實例方法就相當於運行結果。所以很多模板調用錯誤是在編譯階段指出來的。     
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved