文章目录
为什么需要函数包装器函数包装器bind调整可调用类型的参数
为什么需要函数包装器
function函数包装器也叫适配器,在C++中其本质是一个类模板。
由于C++的历史遗留问题,导致如果想实现一个函数功能,可以采用函数名、函数指针、仿函数、有名称的lambda表达式,所有这些都是可调用的类型。 它们存在很多问题:
函数指针类型太复杂,不方便使用和理解仿函数类型是一个类名,没有指定调用参数和返回值,得去看operator()的实现才能看出来。lambda表达式在语法层,看不到类型,只能在底层看到其类型,基本都是lambda_uuid。
比如ret=func(x)这个函数调用,func有可能是上面的任意一种。
类型如此丰富,可能导致模板的效率极低。
#include
using namespace std;
template
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;
cout << useF([](double d)->double {return d / 4; }, 11.11) << endl;
return 0;
}
编译器会根据传入的F类型不同,实例化出三种不同的函数,所以静态变量count就会有三种不同的地址。
很显然这并不很合适,因为不管是函数名、函数指针、仿函数还是lambda表达式,它们都是一个“函数”,所以如果它们能够统一类型,这样模板就会实例化出一份对象,从而提高效率。
函数包装器
包装器可以很好地解决这个问题,它统一可调用对象类型,并且指定了参数和返回值类型。
function函数包装器的写法为:
function<函数返回值类型(函数参数类型)>包装器名称=要包装的函数。
其在头文件
#include
#include
using namespace std;
template
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;
}
};
class Func
{
public:
static double f1(double i)
{
return i / 4;
}
double f2(double i)
{
return i / 5;
}
};
int main()
{
function
function
function
function
//非静态成员函数要传this指针,因此参数要加上Func,且要取地址
function
//调用包装器包装的函数
cout << func1(11.11) << endl;
cout << func2(11.11) << endl;
cout << func3(11.11) << endl;
cout << func4(11.11) << endl;
//传入非静态成员函数时,要额外传入一个对象
cout << func5(Func(),11.11) << endl;
//func1到func5都会被当做一种类型
cout << useF(func1, 11.11) << endl;
cout << useF(func2, 11.11) << endl;
cout << useF(func3, 11.11) << endl;
cout << useF(func4, 11.11) << endl;
//cout << useF(func5, 11.11) << endl;
return 0;
}
bind调整可调用类型的参数
可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原来对象的参数列表。它可以用来绑定一个类对象,这样调用绑定的成员函数时就不需要传入一个类对象了。
#include
#include
using namespace std;
int Plus(int a, int b)
{
return a + b;
}
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
function
cout << f1(1, 2) << endl;//3
//把plus绑定成一个值+10,相当于只传一个参数,另一个参数固定为10
function
cout << f2(4) << endl;//14
//绑定很好地解决了调用成员函数必须要先出入一个对象的问题,它直接绑定了一个对象
function
cout< //控制传入参数的顺序,将 placeholders::_1和 placeholders::_2交换顺序 //这样传入的第一个参数就会作为sub(int a,int b)中的b,第二个参数作为a //这主要是因为_2是和b绑定的,_1和a绑定,先传入的参数是_2,再传入_1 function cout << f4(1, 2) << endl;//1 return 0; }