本文来自《深入应用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被称做可调用对象
(2)是一个具有operator()成员函数的类对象(仿函数)
#include<iostream>
using namespace std;struct Foo
{void operator()(){}
};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){}operator fr_t(){return func;}
};int main()
{Bar bar; //3.可被转换为函数指针的类对象bar();return 0;
}
bar被称做可调用对象,其类型被统称为“可调用类型”。
类型转换运算符: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可以取代函数指针的作用。因为它可以保存函数延迟执行,所以比较适合作为回调函数。