C++98里面的可调用对象只有普通函数和函数指针。
而在C++11里面可调用的对象有下面几种:
在C++11里面有多种类型的可调用对象,包装器可以将这些对象包装起来,给我们提供一个统一的视角。相当于给外面再套了一层盒子。
包装器的定义
//1
template <class T> function; // undefined
//2
template <class Ret, class... Args>
class function<Ret(Args...)>;
它的定义貌似很奇怪,包装器提供了模板,2是1的特化,Ret指出可调用对象的返回值类型,并且给我们提供了可变参数,用一个省略号...
指出模板参数或函数参数是一个包。
function包含在头文件std
域里
包装方式:function<返回类型(参数类型1,参数类型2,...., 参数类型n)> name = 可调用对象
使用方式:name(参数1, 参数2, ...,参数n)
使用方式类似于函数
例一:包装普通函数
#include
#include
using namespace std;
int f(int x, int y)
{
return x - y;
}
int main(void)
{
//用包装器包装起来
function<int(int, int)> f1 = f;
cout << f1(2, 1) << endl;
return 0;
}
例二:包装lambda表达式
//包装可调用对象lambda表达式
function<int(char, char, char)> f2 = [](char e1, char e2, char e3)mutable->int{
return e1 - e2 + e3;
};
cout << f2('z', 'a', 'x') << endl;
例三:包装仿函数
class Student
{
public:
//重载(),仿函数
char operator()(string str)
{
return str[0];
}
};
//包装可调用对象,仿函数
function<char(string)> f3 = Student();
cout << f3("hello") << endl;
在某些情况下我们可能需要提供一个统一的接口来接收这些类型,就需要使用到包装器。
包装器一般会和std::bind
结合使用
std::bind在包装器中有如下作用
作用1:调整参数顺序
作用2:调整参数个数
simple(1)
template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
with return type (2)
template <class Ret, class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
bind在包装器里面的作用简单来说就是利用旧的可调用对象创建了一个新的。第一个参数是一个万能引用,用来接收可调用对象,而它使用后面的参数包指明新对象的函数参数。
int f(int x, int y)
{
return x - y;
}
//用包装器包装起来
function<int(int, int)> f1 = f; //普通函数
cout << f1(2, 1) << endl;
//使用bind
function<int(int, int)> ff1 = bind(f, placeholders::_1, placeholders::_2);
cout << ff1(2, 1);
在使用std::bind
的时候,使用placeholders::_n
指明旧的可调用对象的参数,n对应参数在原来的参数列表里是第几个。这里的placeholders::_1指的就是x。
那么我们可以利用bind来调整参数的顺序
function<int(int, int)> ff1 = bind(f, placeholders::_2, placeholders::_1);
一些特定情况下,某个参数的值是固定的。调整参数的个数,实际上调整的是bind新创建对象的参数。
function<int(int)> f4 = bind(f, 95, placeholders::_1);
cout << f4(12) << endl;
对于对象f来说,它调用的时候需要两个int类型的参数。当我们进行如上操作的时候,将第一个参数固定成了95,调用的时候,就只需要传递一个参数就可以。
使用bind调整参数个数时需要注意