C++函数包装器

C++函数包装器

文章目录

为什么需要函数包装器函数包装器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()

{

functionfunc1 = f;

functionfunc2 = Functor();

functionfunc3 = [](double d)->double {return d / 4; };

functionfunc4 = Func::f1;

//非静态成员函数要传this指针,因此参数要加上Func,且要取地址

functionfunc5 = &Func::f2;

//调用包装器包装的函数

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()

{

functionf1=bind(Plus, placeholders::_1, placeholders::_2);

cout << f1(1, 2) << endl;//3

//把plus绑定成一个值+10,相当于只传一个参数,另一个参数固定为10

functionf2 = bind(Plus, 10, placeholders::_1);

cout << f2(4) << endl;//14

//绑定很好地解决了调用成员函数必须要先出入一个对象的问题,它直接绑定了一个对象

functionf3 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);

cout<

//控制传入参数的顺序,将 placeholders::_1和 placeholders::_2交换顺序

//这样传入的第一个参数就会作为sub(int a,int b)中的b,第二个参数作为a

//这主要是因为_2是和b绑定的,_1和a绑定,先传入的参数是_2,再传入_1

functionf4 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);

cout << f4(1, 2) << endl;//1

return 0;

}