zoukankan      html  css  js  c++  java
  • C++11中的std::bind

    C++11中的std::bind

    最近在看看cocos2dx的源代码,发现了cocos2dx 3.0相对于2.0改动了很多,最大的改变就是大量的使用了C++11的特性,比如auto等。其中有一个关于回调函数绑定的宏定义就使用了std::bind特性

    // new callbacks based on C++11
    #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
    #define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
    #define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
    #define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

    非常简练的宏定义,对于没有接触过C++11的朋友来说,真的是一头雾水,这货是什么,真的是C++吗?所以笔者就写了这篇文章来讲解。

    C++发展的历史

    C++经过多年发展,真正正式公布出的标准只有三个C++98,C++03,C++11。其中C++03只是C++98的小幅度修订,在笔者看来,C++发展的历史,就是一个不断吸收新特性的历史。从最早的面向过程,面向对象,模板编程,到现在的函数式编程,C++一直都是在吸收新特性。lambda就是函数式编程闭包的特性。

    何为bind

    bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调 用实体,这种机制在回调函数的使用过程中也颇为有用。其实最早在C++98的时候,就已经有了std::bind1st和std::bind2nd分别用来绑定functor的两个参数,具体代码就不演示了,查查资料就知道了。这个特性在当时并没有引起太多的重视,可以说是食之无味。
    C++11中提供了std::bind,可以说是一种飞跃的提升,bind本身是一种延迟计算的思想,它本身可以绑定普通函数、全局函数、静态函数、类静态函数甚至是类成员函数。

    #include <iostream>
    #include <functional>
    using namespace std;
    
    int TestFunc(int a, char c, float f)
    {
        cout << a << endl;
        cout << c << endl;
        cout << f << endl;
    
        return a;
    }
    
    int main()
    {
        auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1);
        bindFunc1(10);
    
        cout << "=================================
    ";
    
        auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
        bindFunc2('B', 10);
    
        cout << "=================================
    ";
    
        auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
        bindFunc3(100.1, 30, 'C');
    
        return 0;
    }

    从上面的代码可以看到,bind能够在绑定时候就同时绑定一部分参数,未提供的参数则使用占位符表示,然后在运行时传入实际的参数值。

    PS:绑定的参数将会以值传递的方式传递给具体函数,占位符将会以引用传递。

    众所周知,静态成员函数其实可以看做是全局函数,而非静态成员函数则需要传递this指针作为第一个参数,所以std::bind能很容易地绑定成员函数。
    cocos2dx中的CC_CALLBACK系列的宏其实就是一种封装好的std::bind,它默认认为绑定的就是成员函数,帮助开发者简化了代码。

    总结

    bind最终将会生成一个可调用对象,这个对象可以直接赋值给std::function对象,而std::bind绑定的可调用对象可以是Lambda表达式或者类成员函数等可调用对象,这个是cocos2dx中的一般用法。它能随意绑定任何函数,将所有的函数都能统一到std::function

    example:

    #include <iostream>
    #include <typeinfo>
    #include <functional>
    #include <string.h>
    #include <iostream>
    #include <typeinfo>
    #include <functional>
    #include <string.h>
    using namespace std;
    
    int add(int a, int b, int c)
    {
            return a+b+c;
    }
    
    class Utils{
    public:
            Utils(const char* name){
                    strcpy(_name, name);
            }
    
            void SayHello(const char* name) const{
                    std::cout<<_name<<" say : hello "<<name<<endl;
            }
    
            static int getId(){
                    return 1001;
            }
    
    
    private:
            char _name[32];
    };
    
    int main()
    {
            auto add2 = std::bind(add, std::placeholders::_1, 1, 2);
            int i=add2(5);
            std::cout<<i<<std::endl;
            std::cout<<typeid(add2).name()<<endl;
    
            cout<<"------------------------------------"<<endl;
    
            Utils util("xiaoming");
            //绑定类成员
            auto sayHello = std::bind(&Utils::SayHello, util, std::placeholders::_1);
            sayHello("xiaodonmg");
    
            auto SayHelloKit = std::bind(&Utils::SayHello, util, "kit");
            SayHelloKit();
    
    
            //绑定静态成员
            auto getId = std::bind(&Utils::getId);
            cout<<getId()<<endl;
    
    
    
            return 0;
    }
  • 相关阅读:
    冒泡排序法
    冒泡排序法
    【HAOI2008】圆上的整点
    2018年全国多校算法寒假训练营练习比赛(第四场)F:Call to your teacher
    (java)Jsoup爬虫学习--获取网页所有的图片,链接和其他信息,并检查url和文本信息
    CSS 选择器
    (java)selenium webdriver学习---实现简单的翻页,将页面内容的标题和标题链接取出
    (java)selenium webdriver学习---三种等待时间方法:显式等待,隐式等待,强制等待
    使用D3绘制图表(5)--水平柱状图表
    使用D3绘制图表(4)--面积图表
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/12051702.html
Copyright © 2011-2022 走看看