C++函数包装器

文章目录

  • 为什么需要函数包装器
  • 函数包装器
  • bind调整可调用类型的参数


为什么需要函数包装器

function函数包装器也叫适配器,在C++中其本质是一个类模板。

由于C++的历史遗留问题,导致如果想实现一个函数功能,可以采用函数名、函数指针、仿函数、有名称的lambda表达式,所有这些都是可调用的类型。
它们存在很多问题:

  1. 函数指针类型太复杂,不方便使用和理解
  2. 仿函数类型是一个类名,没有指定调用参数和返回值,得去看operator()的实现才能看出来。
  3. lambda表达式在语法层,看不到类型,只能在底层看到其类型,基本都是lambda_uuid。

比如ret=func(x)这个函数调用,func有可能是上面的任意一种。

类型如此丰富,可能导致模板的效率极低。

#include
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;
	cout << useF([](double d)->double {return d / 4; }, 11.11) << endl;

	return 0;
}

C++函数包装器_第1张图片

编译器会根据传入的F类型不同,实例化出三种不同的函数,所以静态变量count就会有三种不同的地址。

很显然这并不很合适,因为不管是函数名、函数指针、仿函数还是lambda表达式,它们都是一个“函数”,所以如果它们能够统一类型,这样模板就会实例化出一份对象,从而提高效率。


函数包装器

包装器可以很好地解决这个问题,它统一可调用对象类型,并且指定了参数和返回值类型。

function函数包装器的写法为:

function<函数返回值类型(函数参数类型)>包装器名称=要包装的函数。

其在头文件

#include
#include
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;
	}
};
class Func
{
public:
	static double f1(double i)
	{
		return i / 4;
	}
	double f2(double i)
	{
		return i / 5;
	}
};
int main()
{
	function<double(double)>func1 = f;
	function<double(double)>func2 = Functor();
	function<double(double)>func3 = [](double d)->double {return d / 4; };
	function<double(double)>func4 = Func::f1;
	//非静态成员函数要传this指针,因此参数要加上Func,且要取地址
	function<double(Func,double)>func5 = &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;
}

C++函数包装器_第2张图片


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<int(int,int)>f1=bind(Plus, placeholders::_1, placeholders::_2);
	cout << f1(1, 2) << endl;//3

	//把plus绑定成一个值+10,相当于只传一个参数,另一个参数固定为10
	function<int(int)>f2 = bind(Plus, 10, placeholders::_1);
	cout << f2(4) << endl;//14

	//绑定很好地解决了调用成员函数必须要先出入一个对象的问题,它直接绑定了一个对象
	function<int(int, int)>f3 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);
	cout<<f3(1, 2) << endl;//-1

	//控制传入参数的顺序,将 placeholders::_1和 placeholders::_2交换顺序
	//这样传入的第一个参数就会作为sub(int a,int b)中的b,第二个参数作为a
	//这主要是因为_2是和b绑定的,_1和a绑定,先传入的参数是_2,再传入_1
	function<int(int, int)>f4 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
	cout << f4(1, 2) << endl;//1

	return 0;
}

你可能感兴趣的:(C++,c++)