std::function和bind绑定器

本文来自《深入应用C++11 代码优化与工程级应用》

std::function和std::bind,使我们使用标准库函数时更加方便,且还能方便地实现延迟求值


1.可调用对象(Callable Objects)

什么是可调用对象呢?

可调用对象有如下几种定义:

(1)是一个函数指针
#include<iostream>
using namespace std;

void func()
{
    
}

int main()
{
    void(* func_ptr)(void) = &func; //1.函数指针
    func_ptr();
    return 0;
}

func_ptr被称做可调用对象

ps:

测试与验证:

#include<iostream>
using namespace std;

void func()
{
    cout << "func()" << endl;
}

int main()
{
    void(* func_ptr)(void) = &func; //函数指针
    func_ptr();
    void(* func_ptr1)(void) = func; //函数指针
    func_ptr1();
    return 0;
}

(2)是一个具有operator()成员函数的类对象(仿函数
#include<iostream>
using namespace std;

struct Foo
{
    void operator()()
    {
        cout << "Foo__" << endl;
    }
};

int main()
{
    Foo foo;    //2.仿函数
    foo();
    return 0;
}

foo被称做可调用对象

(3)是一个可被转换为函数指针的类对象。

#include<iostream>
using namespace std;

struct Bar
{
    using fr_t = void(*)(void);

    static void func(void)
    {
        cout << "static void fun(void);" << endl;
    }

    operator fr_t()
    {
        return func;
    }
};

int main()
{
    Bar bar;    //3.可被转换为函数指针的类对象
    bar();
    return 0;
}

bar被称做可调用对象(Callable objects),其类型(Class)被统称为“可调用类型”(Callable Class)。   

 类型转换运算符:operator 类型()-CSDN博客

(4)是一个类成员(函数)指针。

#include<iostream>
using namespace std;

struct A
{
    int a_;
    void men_func()
    {
        
    }
};

int main()
{
    void (A::*mem_func_ptr)(void)   //4.类成员函数指针
            = &A::men_func;
    int A::*mem_obj_ptr //类成员指针
            = &A::a_;
    
    A aa;
    (aa.*mem_func_ptr)();
    aa.*mem_obj_ptr = 123;
    return 0;
}

mem_func_ptr,mem_obj_ptr被称做可调用对象

从上面4个例子可以看到,除了类成员函数之外,上面定义涉及的对象均可以像一个函数那样做调用操作。

func_ptr,foo,mem_func_ptr,mem_obj_ptr都被称为可调用对象,这些对象的类型被称为“可调用类型”。

可调用对象的定义中不包括函数类型和函数引用,包括函数指针。

因为函数类型不能用来直接定义对象。

函数引用从某种意义上来说,可以看做一个const的函数指针。

C++中的可调用对象虽然有比较统一的操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法五花八门。当我们试图使用统一的方式保存,或传递一个可调用对象时,会非常麻烦。

2.可调用对象包装器---std::function

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

#include<iostream>
#include <functional>

void func(void)
{
    std::cout << __FUNCTION__ << std::endl;
}

class Foo
{
public:
    static int foo_func(int a)
    {
        std::cout << __FUNCTION__ << "(" << a << ") ->: ";
        return a;
    }
};

class Bar
{
public:
    int operator()(int a)
    {
        std::cout << __FUNCTION__ << "(" << a << ") ->: ";
        return a;
    }
};

int main()
{
    std::function<void(void)> fr1 = func; //绑定一个普通函数
    fr1();

    //绑定一个类的静态成员函数
    std::function<int(int)> fr2 = Foo::foo_func;
    std::cout << fr2(123) << std::endl;

    //绑定一个仿函数
    Bar bar;
    fr2 = bar;
    std::cout << fr2(123) << std::endl;
    return 0;
}

输出结果: 

func

foo_func(123) ->: 123

operator()(123) ->: 123

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

#include<iostream>
#include <functional>

class A
{
    std::function<void()> callback_;
public:
    A(const std::function<void()>& f)
        : callback_(f)
    {}
    void notify(void)
    {
        callback_();
    }
};

class Foo
{
public:
    void operator()(void)
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

int main()
{
    Foo foo;
    A aa(foo);
    aa.notify();
    return 0;
}

输出:

operator()

可以看出,std::function可以取代函数指针的作用。因为它可以保存函数延迟执行,所以比较适合作为回调函数。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伸头看云朵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值