• C++11 学习笔记 std::function和bind绑定器


    1.1 可调用对象(Callable Objects)

    可调用对象有如下几种:

    • 函数指针
    • 具有operator()成员函数的类对象(仿函数)
    • 可被转换为函数指针的类对象
    • 类成员(函数)指针

    以上涉及的对象可以像一个函数一样做调用操作,统称为可调用对象。现在,C++11通过提供std::function和std::bind统一了可调用对象的各种操作。

    1.2 可调用对象包装器——std::function

    C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法五花八门。为了统一泛化函数对象,函数指针,引用函数,成员函数的指针的各种操作,让我们可以按更统一的方式写出更加泛化的代码,C++11推出了std::function。

      std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执行它们。

    #include <iostream>
    #include <functional>
     
    using namespace std;
     
     void func(void){
         cout << __FUNCTION__ <<endl;
     }
     
     class Foo
     {
     public:
         static int foo_func(int a){
             cout << __FUNCTION__ << "(" << a << ") ->: ";
             return a;
         }
     };
     
     class Bar
     {
     public:
         int operator()(int a){
             cout << __FUNCTION__ << "(" << a << ") ->: ";
             return a;
         }
     };
     
     int main(){
         //綁定一個普通函數
         std::function<void(void)> fry = func;
         fry();
     
         
         //綁定一個類的靜態成員函數
         std::function<int(int)> fr2 = Foo::foo_func;
         cout << fr2(123) << endl;
         
         //綁定一個仿函數
         Bar bar;
         fr2 = bar;
         cout << fr2(123) <<endl;
     
         return 0;
     }
    root@ubuntu:~/c++# g++ -std=c++11 func1.cpp -o func
    root@ubuntu:~/c++# ./func 
    func
    foo_func(123) ->: 123
    operator()(123) ->: 123
    root@ubuntu:~/c++# 

     std::function的使用方法:我们给std::function填入合适的函数签名(即一个函数类型,只需要包括返回值和参数表)之后,它就变成了一个可以容纳所有这一类调用方式的“函数包装器”。

    #include <iostream>
    #include <functional>
     
    using namespace std;
     
     class A
     {
     public:
         A(const std::function<void()>& f) :callback_(f){}
         
         void notify(void){
             callback_();
         }
     private:
         std::function<void()> callback_;
     };
     
     class Foo
     {
     public:
         void operator()(void){
             cout <<"in " <<  __FUNCTION__<< endl;
         }
     };
     
     int main(){
         Foo foo;
         A aa(foo);
         aa.notify();
         
         return 0;
     }
    "func2.cpp" 32L, 452C written                                                                                                              
    root@ubuntu:~/c++# g++ -std=c++11 func2.cpp -o func
    root@ubuntu:~/c++# ./func
    in operator()

    C++11 std::function 是一种通用、多态的函数封装,它的实例可以对任何可以调用的目标实体进行存储、复制和调用操作,它也是对 C++中现有的可调用实体的一种类型安全的包裹(相对来说,函数指针的调用不是类型安全的),换句话说,就是函数的容器。当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理。例如:

    lambda函数

    std::bind绑定器

      std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。通俗来讲,它主要有两大作用:

      1).将可调用对象与其参数一起绑定成一个仿函数。

      2).将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。

      function模板类和bind模板函数,都可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类的非静态成员函数时。

      1).std::function可以绑定到全局函数/类静态成员函数(类静态成员函数与全局函数没有区别)。

      2).绑定到类的非静态成员函数,则需要使用std::bind。

    #include <iostream>
     #include <functional>
     
     using namespace std;
     
     void call_when_even(int x, const std::function<void(int)>& f){
         if(!(x & 1)){
             f(x);
         }
     }
     
     void output(int x){
         cout << x << " ";
     }
     
     void output_add_2(int x){
         cout << x +2 << " ";
     }
     
     int main(){
         {
             auto fr = std::bind(output, std::placeholders::_1);
             for(int i=0;i<10;i++){
                call_when_even(i, fr);
             }
             cout << endl;
         }
         
         {
             auto fr = std::bind(output_add_2, std::placeholders::_1);
             for(int i=0;i<10;i++){
                 call_when_even(i, fr);
             }
             cout << endl;
         }
     
         return 0;
     }
    root@ubuntu:~/c++# ./bind
    0 2 4 6 8 
    2 4 6 8 10 
    root@ubuntu:~/c++# 

     "std::placeholders::_1"是一个占位符对象,用于表示当函数output(output_add_2)通过函数fr进行调用时,函数fr的第一个参数在函数output(output_add_2)的参数列表中的位置。

    #include <iostream>
     #include <functional>
     
     using namespace std;
     
     class A
     {
     public:
         int i_=0;
     
         void output(int x, int y){
             cout << x << " " << y <<endl;
         }
     };
     
     int main(){
         A a;
         std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1,std::placeholders::_2);
         fr(1,2);
     
         std::function<int&(void)> fr_i = std::bind(&A::i_, &a);
         fr_i() = 123;
         cout << a.i_ << endl;
     
         return 0;
     }
    root@ubuntu:~/c++# g++ -std=c++11 bind.cpp -o bind
    root@ubuntu:~/c++# ./bind
    1 2
    123
    #include <iostream>
     #include <functional>
    #include <functional>
    #include <string>
    #include <iostream>
     
    void goodbye(const std::string& s)
    {
        std::cout << "Goodbye " << s << '
    ';
    }
     
    class Object {
    public:
        void hello(const std::string& s)
        {
            std::cout << "Hello " << s << '
    ';
        }
    };
     
    int main(int argc, char* argv[])
    {
        typedef std::function<void(const std::string&)> ExampleFunction;
        Object instance;
        std::string str("World");
        ExampleFunction f = std::bind(&Object::hello, &instance, 
                                      std::placeholders::_1);
     
        // equivalent to instance.hello(str)
        f(str);
        f = std::bind(&goodbye, std::placeholders::_1);
     
        // equivalent to goodbye(str)
        f(str);    
        return 0;
    }
    root@ubuntu:~/c++# ./bind
    Hello World
    Goodbye World
    root@ubuntu:~/c++# 


     

  • 相关阅读:
    vbs小脚本01将文件内txt转录到excel
    MybatisPlus乐观锁Version
    PHP使用pdfparser实现对PDF转换成本文
    php获取图片的主要颜色值RGB
    nginx http跳转到https
    java 获取中文第一个拼音方法
    mysql like查询时区分字母大小写
    mysql 查询用逗号隔开字符串的关键字
    Fiddler 手机抓包
    携程爬虫
  • 原文地址:https://www.cnblogs.com/dream397/p/15078219.html
Copyright © 2020-2023  润新知