当前位置:首页 > 公众号精选 > 码农爱学习

本篇来介绍了C++中bind功能。

1 std::bind

在 C++ 里,std::bind 是一个函数模板,其作用是创建一个可调用对象,该对象可绑定到一组参数上。std::bind 的函数原型如下:

template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );


template< class R, class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );

参数

  • F:这是要绑定的可调用对象(像函数、函数指针、成员函数指针、函数对象等)的类型。
  • Args:这是要绑定的参数的类型包。
  • f:需要绑定的可调用对象。
  • args:要绑定到可调用对象上的参数。
  • R:可调用对象的返回类型(可选)。

返回值

  • std::bind 返回一个未指定类型的可调用对象,这个对象存储了 f 和 args 的副本或者引用,并且可以在后续被调用。

2 实例

2.1 基础的bind功能 

被绑定的函数支持参数和返回值,参数通过std::placeholders::_1的形式,注意这里_1是特定的形式,表示第一个参数

//g++ test1.cpp -std=c++11 -o test1
#include 
#include 


std::string myFunc(int a, float b)
{
    char buf[256];
    sprintf(buf, "receive a:%d, b:%.2f", a, b);
    returnstd::string(buf);
}

int main()
{
    auto bindFunc = std::bind(myFunc, std::placeholders::_1, std::placeholders::_2);
    std::string res = bindFunc(5, 8.63);
    printf("res:%s\n", res.c_str());
    
    return0;
}

示例代码运行结果如下:

2.2 bind时调换参数的顺序 

如果调换参数顺序的需求,可以通过指定placeholders的顺序,来实现。

比如,myFunc的第二个参数是float类型,如果在执行调用函数时,第一个参数传入float,则在绑定函数的第一个位置,写为 std::placeholders::_2即可。

//g++ test2.cpp -std=c++11 -o test2
#include 
#include 


std::string myFunc(int a, float b)
{
    char buf[256];
    sprintf(buf, "receive a:%d, b:%.2f", a, b);
    returnstd::string(buf);
}

int main()
{
    auto bindFunc = std::bind(myFunc, std::placeholders::_2, std::placeholders::_1);
    std::string res = bindFunc(3.14, 6);
    printf("res:%s\n", res.c_str());
    
    return0;
}

示例代码运行结果如下:

2.3 结合C++类使用bind 

上面介绍的函数都不涉及到类,而C++中一般都会使用类,在类中以及类中的函数,如果使用bind,主要区别就是要再额外传入对应的类的指针。

这里演示了3种情况:

  • MyClass1进行一个实例化,然后在main中bind其成员函数
  • MyClass2是一个单例模式,在main中bind的时候进行实例化
  • MyClass3,演示在类内部进行bind,类的指针就是this指针
//g++ test3.cpp -std=c++11 -o test3
#include 
#include 


class MyClass1
{

public:
    std::string myFunc(int a, float b)
    
{
        char buf[256];
        sprintf(buf, "receive a:%d, b:%.2f", a, b);
        returnstd::string(buf);
    }    
};

class MyClass2
{

public:
    static MyClass2 &getInstance()
    
{
        static MyClass2 instance;
        return instance;
    }
    
    std::string myFunc(int a, float b)
    
{
        char buf[256];
        sprintf(buf, "receive a:%d, b:%.2f", a, b);
        returnstd::string(buf);
    }    
};

class MyClass3
{

public:
    std::string myFunc(int a, float b)
    
{
        char buf[256];
        sprintf(buf, "receive a:%d, b:%.2f", a, b);
        returnstd::string(buf);
    } 
    
    void testBind()
    
{
        auto bindFunc = std::bind(&MyClass3::myFunc, this, std::placeholders::_1, std::placeholders::_2);
        std::string res = bindFunc(33, 3.45);
        printf("res:%s\n", res.c_str()); 
    }  
};

int main()
{
    MyClass1 myClass1;
    auto bindFunc1 = std::bind(&MyClass1::myFunc, &myClass1, std::placeholders::_1, std::placeholders::_2);
    std::string res1 = bindFunc1(11, 1.23);
    printf("res:%s\n", res1.c_str());

    auto bindFunc2 = std::bind(&MyClass2::myFunc, MyClass2::getInstance(), std::placeholders::_1, std::placeholders::_2);
    std::string res2 = bindFunc1(22, 2.34);
    printf("res:%s\n", res2.c_str());
    
    MyClass3 myClass3;
    myClass3.testBind();
      
    return0;
}

示例代码运行结果如下:

2.4 std::ref的使用 

在进行bind的时候,也可以不使用placeholders占符,直接传入具体的参数。

这里要注意,直接传入值,即使函数参数定义的是引用,但实际效果也是按值传递。如果需要按引用传递,需要使用std::ref,如下例中的第一个演示。当然,如果是使用placeholders占符,就不需要考虑std::ref了,就会正常的按定义的引用类型运行。

//g++ test4.cpp -std=c++11 -o test4
#include 
#include 


std::string myFunc(int &a, float &b)
{
    char buf[256];
    sprintf(buf, "receive a:%d, b:%.2f", a, b);
    a += 1;
    b += 1;
    returnstd::string(buf);
}

int main()
{
    int a = 100;
    float b = 66.88;
    printf("a:%d, b:%.2f\n", a, b);
    auto bindFunc1 = std::bind(myFunc, a, std::ref(b));
    std::string res1 = bindFunc1();
    printf("res1:%s\n", res1.c_str());
    printf("a:%d, b:%.2f\n", a, b);
    
    auto bindFunc2 = std::bind(myFunc, std::placeholders::_1, std::placeholders::_2);
    std::string res2 = bindFunc2(a, b);
    printf("res2:%s\n", res2.c_str());
    printf("a:%d, b:%.2f\n", a, b);
    
    return0;
}

示例代码运行结果如下:

2.5 将bind作为函数参数实现函数传递 

最后来看一个特殊的,函数的参数是一个函数类型,如下面的MyClass类中的myFunc,它需要传入一个函数,这个函数有两个float类型的参数,并且返回一个float,在myFunc中定义了两个参数的具体的值。

这个有什么用呢,比如在MyCalc类中定义sum求和函数和sub求差函数,这样MyClass类就可以使用外部的MyCalc类中定义的函数功能,来实现一些数学运算。

//g++ test5.cpp -std=c++11 -o test5
#include 
#include 

class MyCalc
{

public:
    float sum(float a, float b)
    
{
        return a + b;
    }

    float sub(float a, float b)
    
{
        return a - b;
    }
};

class MyClass
{

public:
    void myFunc(std::function<float(float,float)> calcFunc)
    
{
        float a = 55;
        float b = 22;
        float res = calcFunc(a, b);
        printf("a:%.2f, b:%.2f, res:%.2f\n", a, b, res);
    }
};

int main()
{
    MyCalc myCalc;
    MyClass myClass;
    
    auto bindFunc1 = std::bind(&MyCalc::sum, &myCalc, std::placeholders::_1, std::placeholders::_2);
    myClass.myFunc(bindFunc1);
    
    auto bindFunc2 = std::bind(&MyCalc::sub, &myCalc, std::placeholders::_1, std::placeholders::_2);
    myClass.myFunc(bindFunc2);
    
    return0;
}

示例代码运行结果如下:

3 总结

本篇介绍了C++中bind功能的使用,并通过实际的例里来演示其使用场景。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭