包装器
- 📖1. 为什么需要包装器
- 📖2. 如何使用包装器
- 📖3. bind函数
📖1. 为什么需要包装器
包装器也叫做适配器,C++中的function
本质是一个类模板,也是一个包装器.
为什么需要function
呢?
我们来看一个例子:
ret = func(x);
//上面的func可能是函数名, 函数对象, 也有可能是lambda表达式, 这些都是可调用的类型, 如此丰富的类型, 可能会导致模板的效率低下
//例如下面这段代码
#include <iostream>
using namespace std;
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count: " << ++count << endl;
cout << "count: " << &count << endl;
return f(x);
}
//函数
double f(double i)
{
return i / 2;
}
//函数对象
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数
cout << useF(f, 11.11) << endl;
//函数对象
cout << useF(Functor(), 11.11) << endl;
//lambda表达式
cout << useF([](double d)->double {return d / 4; }, 11.11);
return 0;
}
最终这个模板实例化出了三份.
📖2. 如何使用包装器
包装器可以很好的解决上面的问题:
std::function 在头文件 <functional>
//包装器原型如下
template<class T> function;
template<class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:
Ret: 被调用函数的返回类型
Args: 被调用函数的形参
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
//包装函数
function<int(int, int)> func1 = f;
cout << func1(1, 2) << endl;
//包装函数对象
function<int(int, int)> func2 = Functor();
cout << func2(1, 2) << endl;
//包装lambda表达式
function<int(int, int)> func3 = [](const int a, const int b) {return a + b; };
cout << func3(1, 2) << endl;
//包装类的成员函数(静态)
function<int(int, int)> func4 = &Plus::plusi;
cout << func4(1, 2) << endl;
//包装类的成员函数(非静态)
function<double(Plus, double, double)> func5 = &Plus::plusd;
cout << func5(Plus(), 1.1, 1.2) << endl;
return 0;
}
那么,包装器是如何解决了模板的效率低下,实例化了多份的问题呢?
#include <iostream>
#include <functional>
using namespace std;
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count: " << ++count << endl;
cout << "count: " << &count << endl;
return f(x);
}
//函数
double f(double i)
{
return i / 2;
}
//函数对象
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数
function<double(double)> func1 = f;
cout << useF(func1, 11.11) << endl;
//函数对象
function<double(double)> func2 = Functor();
cout << useF(func2, 11.11) << endl;
//lambda表达式
function<double(double)> func3 = [](double d)->double {return d / 4; };
cout << useF(func3, 11.11);
return 0;
}
有了包装器以后,模板只实例化了一份.
📖3. bind函数
std::bind
函数定义在functional
头文件中,是一个函数模板,它就像一个函数包装器(适配器),接收一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表.
原型如下:
template<class Fn, class... Args>
bind(Fn&& fn, Args&&... args);
template<class Ret, class Fn, class... Args>
bind(Fn&& fn, Args&&... Args);
可以将bind
函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来 “适应” 原对象的参数列表.
调用bind的一般形式:auto newCallable = bind(callable, arg_list);
其中,newCallable
本身是一个可调用对象,arg_list
是一个逗号分隔的参数列表,对应给定的callable的参数,当我们调用newcallable
的时,newCallable
会调用callable
,并传给它arg_list
的参数.
arg_list
中的参数可能包含形如_n
的名字,其中n是一个整数,这些参数是占位符,表示newCallable
中的参数,它们占据了传递给newCallable
的参数的"位置":_1
为newCallable
的第一个参数,_2
为第二个参数,以此类推.
用法:
int Plus(int a, int b)
{
return a + b;
}
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
//表示绑定函数Plus 参数分别由调用 func1 的第一、二个参数指定
function<int(int, int)> func1 = bind(Plus, placeholders::_1, placeholders::_2);
auto func2 = bind(Plus, 1, 2);
cout << func1(1, 2) << endl;
cout << func2() << endl;
//绑定成员函数
function<int(int, int)> func3 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);
//参数调换顺序
function<int(int, int)> func4 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
cout << func3(1, 2) << endl;
cout << func4(1, 2) << endl;
return 0;
}