C++:基础记录:std::bind用法整理

        参考文档:

【C++11】std::bind及std::placeholders_我要精通C++的博客-CSDN博客_std::bind std::placeholders

C++ std::bind用法详解_C 语言_脚本之家

1:摘自《Effective Modern C++》中一段对std::bind描述的话

std::bind is the C++11 successor to C++98’s std::bind1st and std::bind2nd,
but, informally, it’s been part of the Standard Library since 2005. That’s when the
Standardization Committee adopted a document known as TR1, which included
bind’s specification. (In TR1, bind was in a different namespace, so it was
std::tr1::bind, not std::bind, and a few interface details were different.) This
history means that some programmers have a decade or more of experience using
std::bind. If you’re one of them, you may be reluctant to abandon a tool that’s
served you well. That’s understandable, but in this case, change is good, because in
C++11, lambdas are almost always a better choice than std::bind. As of C++14, the
case for lambdas isn’t just stronger, it’s downright ironclad.
 
 
std::bind是C++11对C++98中对std::bind1st和std::bind2nd的继承,但是,非正式地说,
它自2005年以来一直是标准库的一部分.标准化委员会通过了一份称为TR1的文件,其中包
括bind的具体实现(在TR1中,bind位于不同
的命名空间中,因此它是std::tr1::bind而不是std::bind,有几个接口细节是不一样的)
这段历史意味着一些程序员有十年或更长时间的使用绑定.如果你是其中之一,你可能不
愿意放弃一个工具,这是可以理解的,但在这种情况下,变化是好的,因为在在C++11中,lambdas
几乎总是比std::bind更好的选择.lambdas(兰布达斯)的理由不仅仅是更有力,而是无懈可击。

学习纲要:

  1. std::bind() 思想,头文件以及原型
  2. std::placeholders()思想,头文件及原型
  3. std::bind() 单独使用(绑定普通函数,绑定类的成员函数,绑定一个引用参数)
  4. std::bind()和std::placeholders混用(减少参数个数,调整参数次序

 std::bind() 思想,头文件以及原型

简介:

  •       std::bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有变量,产生一个新的可调用实体。
  •       可将std::bind函数看做一个通用的函数适配器,它接收一个可调用对象生成一个新的可调用对象来 “适配”原函数参数列表
  • std::bind将原可调用对象与其参数一起绑定后,新的可调用对象可以使用:std::function保存。

作用:

      将可调用对象和其参数变得成一个仿函数

  1.      你绑定原可调用对象参数
  2.       只绑定原可调用对象部分参数,从而可以减少对象传入的参数
  3.       绑定原可调用对象参数次序变换

使用场景:

     先将可调用的对象保存起来,在需要的时候再调用,是一种延迟计算的思想,不论是普通函数,函数对象,还是成员函数,成员变量都可以绑定。

头文件

       #include<functional>

原型:

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-Callable object (function object, pointer to function, reference to function, pointer to member function, or pointer to data member) that will be bound to some arguments
args-

list of arguments to bind, with the unbound arguments replaced by the placeholders _1,

_2, _3... of namespace std::placeholders

  std::bind()::placeholders 思想及作用

#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); //等于TestFunc(10,'A', 100.1)
 
    cout << "=================================\n";
 
    auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
    bindFunc2('B', 10); //等于TestFunc(10,'B', 100.1)
 
    cout << "=================================\n";
 
    auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
    bindFunc3(100.1, 30, 'C'); //等于TestFunc(30,'C', 100.1)
 
    return 0;
}
  1. 上面这段代码主要说的是bind中std::placeholders的使用。 std::placeholders是一个占位符。当使用bind生成一个新的可调用对象时,
  2. std::placeholders表示新的可调用对象的第 几个参数和原函数的第几个参数进行匹配。

 

1: std::bind单独使用,绑定普通函数

double myDivide(double x,double y){
    // 取商
    return x/y;
}


int main(){

   // bind的第一个参数是函数名,普通函数做实参时,会隐式转换成函数指针
   // 所以:sid::bind(myDivide,1,2)等价于std::bind(&myDivide,1,2)

   auto fn_half = bind(myDivide,1,3);
   cout<< fn_half()<< endl;
}

// 打印
0.333333

1.1:std::bind单独使用,绑定类的成员函数 

struct Foo {
    void print_sum(int n1,int n2){
        std::cout << n1+ n2<< '\n';

    }
    int data = 10;
};

int main(){


   /**
        bind 绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址
        必须显示的指定 &Foo::print_sum ,
        因为编译器不会将对象的成员函数隐式转换成函数指针
        所以必须在 Foo::print_sum 前添加 & 
        
        使用对象成员函数的指针时,必须要知道该指针属于哪个对象,因此第二个参数为对象的地址 &foo
   */
    Foo foo;
    auto f = std::bind(&Foo::print_sum,&foo,95,5);
    f(); // 100
}

1.2: std::bind单独使用,绑定一个引用参数 

ostream& print(ostream& os,const string& s, char c){
    os<< s << c;
    return os;
}

int main(){
   
    ostringstream os1;
    // ostream不能拷贝,如果希望传递给bind一个对象,但是不拷贝它。
    // 就必须使用标准库提供的 ref函数。
    for_each(words.begin(),words.end(),
            bind(print,ref(os1),std::placeholders::_1,c));
    cout << os1.str() << endl;

}
打印
hello world this is C++11 

1.3:  使用std::bind和 std::placeholders混用达到减少参数使用和调整参数次序的效果

double myDivide(double x,double y){
    // 取商
    return x/y;
}


int main(){
   
    // std::bind和std::placeholders混用达到减少参数使用和调整参数次序的效果
    
    // 减少一个参数
    auto fn_half_1 = std::bind(myDivide,std::placeholders::_1,2);
    std::cout<< fn_half_1(1) << std::endl;  // myDivie(1,2) 0.5

    // 减少两个参数
    auto fn_half_2 = std::bind(myDivide,1,2);
    std::cout<< fn_half_2()<< std::endl; //  myDivie(1,2) 0.5

    // 将调用的第一个参数和第二个参数互换
    auto fn_half_3 = std::bind(myDivide,std::placeholders::_2,std::placeholders::_1);
    std::cout<< fn_half_3(1,2)<<endl; // myDivide(2,1) // 2

}

1.4: 使用std::bind和std::placeholders达到调整参数次序的效果的另一个例子 

int TestFunc(int a,char c, float f){
    std::cout << a<< std::endl;
    std::cout << c<< std::endl;
    std::cout << f<< std::endl;
    return a;
}

// 第一个参数和函数第一个参数匹配(int),第二个参数和第二个参数匹配(char),第三个参数和第三个参数匹配
auto fun1 = bind(TestFunc,placeholders::_1,placeholders::_2,placeholders::_3);

// 通过占位符调整顺序,第二个参数和原函数第一个参数匹配,第三个参数和原函数第二个参数匹配,第一个参数和原函数第三个函数匹配
auto fun2 = bind(TestFunc,placeholders::_2,placeholders::_3,placeholders::_1);

// 第一个参数和原函数第一个参数匹配,第二个参数和原函数第二个参数匹配,第三个参数默认98.77
auto fun3 = bind(TestFunc,placeholders::_1,placeholders::_2,98.77);

int main(){
    fun1(30,'C',100.1);
    cout<< "-------"<< endl;
    fun2(100.1,30,'C');
    cout<< "-------"<< endl;
    fun3(30,'C');
    cout<< "-------"<< endl;
    fun3(30,'C',9.8);  // 9.8 会被忽略
}

// 打印

30
C
100.1
-------
30
C
100.1
-------
30
C
98.77
-------
30
C
98.77

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值