文档章节

C++标准 bind函数用法与C#简单实现

 天天不在
发布于 2015/02/13 14:19
字数 1182
阅读 16
收藏 0
点赞 0
评论 0

  在看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, " "));
}
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() + 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# 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, 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<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;
View Code

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

  

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 1
码字总数 1182
作品 0
万州
什么是 C 和 C ++ 标准库?

简要介绍编写C/C ++应用程序的领域,标准库的作用以及它是如何在各种操作系统中实现的。 我已经接触C++一段时间了,一开始就让我感到疑惑的是其内部结构:我所使用的内核函数和类从何而来? ...

oschina ⋅ 04/10 ⋅ 0

C语言/C++编程学习:程序结构:构思

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/11 ⋅ 0

C语言编程学习—宏定义的一些使用技巧

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 03/24 ⋅ 0

小朋友学经典算法(12):分割字符串

一、准备知识 在分割字符串之前,先来了解一些跟字符串相关的变量或函数: (1)sizetype:sizetype由string类类型和vector类类型定义的类型,用以保存任意string对象或vector对象的长度,标...

海天一树X ⋅ 06/14 ⋅ 0

C语言/C++编程新手学习常见问题

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/11 ⋅ 0

Java程序员如何高效而优雅地入门C++

Java程序员如何高效而优雅地入门Cpp,由于工作需要,需要用C++写一些模块。关于C++ 的知识结构,虽说我有过快速学习很多新语言的经验,但对于C++ 我也算是老手,但也还需要心生敬畏,本文会从...

小欣妹妹 ⋅ 04/23 ⋅ 0

大神有话说之c++,还在迷茫的朋友可以来看一下

C++ 是一种中级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。C++ 可运行于多种平台上,如 Window...

悟空_b201 ⋅ 05/30 ⋅ 0

SWIG与JAVA 交互最全开发指南一

项目背景 最近开始研究做移动端项目,但是本人基本是做了五六年的c++的底层研发,对C++的研发可以说是驾轻就熟了,但是对于android还是属于刚入门阶段,虽然断断续续做移动端也做了一年,但是...

揽月凡尘 ⋅ 06/16 ⋅ 0

C/C++之C及C++发展史及标准

Tips:  1. 本人当初学习C/C++的记录。  2. 资源很多都是来自网上的,如有版权请及时告知!  3. 可能会有些错误。如果看到,希望能指出,以此共勉! C和C++   C++是C语言的一个超集。C...

zcshoucsdn ⋅ 2017/03/06 ⋅ 0

C语言/C++编程学习异常处理:如何处理c++中的异常

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界 ⋅ 05/12 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

中标麒麟(龙芯版)7.0优盘安装

########################################## 制作U盘安装盘: 1.准备U盘: PMON环境下U盘必须格式化成ext3; 昆仑固件环境下可以格式化成ext3,ext4 2.把整个镜像 xxx.iso 复制到U盘下面 3....

gugudu ⋅ 10分钟前 ⋅ 0

老司机写的大数据建模五步走

本文将尝试来梳理一下数据建模的步骤,以及每一步需要做的工作。 01 第一步:选择模型或自定义模式 这是建模的第一步,我们需要基于业务问题,来决定可以选择哪些可用的模型。 比如,如果要预...

gulf ⋅ 19分钟前 ⋅ 0

PacificA 一致性协议解读

PacificA 的 paper 在 08 年左右发出来的,比 Raft 早了 6,7 年。 在 PacificA 论文中,他们强调该算法使用范围是 LAN (Local Area Network),讲白了就是对跨机房不友好。 不管是 ZAB,Raf...

黑客画家 ⋅ 22分钟前 ⋅ 0

盘符图标个性化

设置自己的专属盘符图标 准备ico格式的图片文件一个,在根目录下创建autorun.inf文件 文件内容 [Autorun]icon=logo.ico 重新启动或者插拔U盘即可看到结果...

阿豪boy ⋅ 22分钟前 ⋅ 0

Windows下QQ聊天记录中图片的默认存放位置

Windows下QQ聊天记录中图片的默认存放位置在设置中是没有说明的。 实测位置在:D:\Documents\Tencent Files\974101467\Image 其中: “974101467”为对应的QQ号; “C2C”为个人之间的聊天图...

临江仙卜算子 ⋅ 28分钟前 ⋅ 0

GC 的三种基本实现方式

参考资料《代码的未来》(作者: [日] 松本行弘)。 由于并非本人原著(我只是个“搬运工“),SO 未经本人允许请尽情转载。 另外个人像说明一下这里所说的GC指泛指垃圾回收机制,而单指Jav...

xixingzhe ⋅ 29分钟前 ⋅ 0

Android双击退出

/** * 菜单、返回键响应 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if(keyCode......

王先森oO ⋅ 33分钟前 ⋅ 0

idea 整合 vue 启动

刚学习Vue 搭建了一个项目 只能命令启动 Idea里面不会启动 尝试了一下修改启动的配置 如下: 1.首先你要保证你的package.json没有修改过 具体原因没有看 因为我改了这个name的值 就没办法启动...

事儿爹 ⋅ 39分钟前 ⋅ 0

redis在windows环境的后台运行方法

在后台运行,首先需要安装redis服务,命令为 redis-server.exe --service-install redis.windows.conf --loglevel verbose 启动,命令为 redis-server --service-start 停止,命令为 redis-...

程序羊 ⋅ 42分钟前 ⋅ 0

比特币现金开发者提出新的交易订单规则

本周,四位比特币现金的四位开发者和研究员:Joannes Vermorel(Lokad),AmaurySéchet(比特币ABC),Shammah Chancellor(比特币ABC)和Tomas van der Wansem(Bitcrust)共同发表了一篇关...

lpy411 ⋅ 46分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部