C++包装器

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

C++包装器

小小酥诶   2022-09-29 我要评论

function

目前,我们的知识深度已知的可调用对象类型有:

  • 函数指针
  • 仿函数 / 函数对象
  • lambda表达式

现在我们有一个函数模板

   template<class F, class T>
   T useF(F f, T x)
   {
  		static int count = 0;
  	  	cout << "count:" << &count << endl;
     	return f(x);
   }

对于函数模板,编译器会根据实参,按照模板定义出一份特定的函数。

函数内部的静态成员变量是属于函数的,无论调用多少次该函数,都只会定义出一个。

记住上面这两个知识点,现在增加一个函数和仿函数,用来测试useF函数模板

int Sub(int num)
{
	return (num - 2);
}
struct Func
{
	int operator()(int num)
	{
		return (num - 3);
	}
};
int main()
{
	// 函数名
	cout << useF(Sub, 4) << endl;
	// 函数对象
	cout << useF(Func(), 4) << endl;
	// lambda表达式
	cout << useF([](int d)->int{ return (d - 4); }, 11.11) << endl;
	return 0;
}

解释运行结果:我们在函数模板内部实现打印静态成员变量,发现三次打印的cout地址不一样。然而静态成员变量是属于函数的,一个函数的静态成员变量无论调用多少次都只有一份。这说明是三个不同的函数调用。

以lambda表达式为例,一个lambda表达式语句就生成一个自定义类型(仿函数),那么多次调用会根据模板产生非常多的函数。

int main()
{
	// 函数名
	cout << useF(Sub, 4) << endl;
	// 函数对象
	cout << useF(Func(), 4) << endl;
	// lamber表达式
	cout << useF([](int d)->int{ return (d - 4); }, 11.11) << endl;
	cout << useF([](int d)->int { return (d - 4); }, 11.11) << endl;
	return 0;
}

其他可调用对象的类型也是很多的,许多的函数指针,许多的仿函数类,许多的lambda表达式……。类型太丰富了!对于一个模板而言,类型不同,就会对应定义出一份。模板的效率也降低了太多。

C++11提供了包装器,包装器可以将可调用对象统一包装成一个类型。function就是一个包装器,也可称为适配器

function

#include <functional>
template <class Ret, class... Args> 
class function<Ret(Args...)>;

Ret(Args…):第一个模板参数类型(参数包)

测试:

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);
}
int main()
{
	function<int(int)> f1 = [](int d)->int { return (d - 4); };
	function<int(int)> f2 = [](int d)->int { return (d - 4); };
	function<int(int)> f3 = [](int d)->int { return (d - 4); };
	// lamber表达式
	cout << useF(f1, 5) << endl;
	cout << useF(f2, 5) << endl;
	cout << useF(f3, 5) << endl;
	return 0;
}

上面调用的都是同一个函数。

一个lambda表达式语句会生成一个类,上面有三个lambda表达式语句,生成三个类。使用function包装器将这些可调用对象包装成了一个类型,模板也就只需要定义出一份特定的,极大地提升了模板的效率。

【普通函数指针】

包装用法:function<Ret(Args...)> 对象名 = 函数指针

//例如
int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//包装函数指针
	function<int(int, int)> f1 = Sub;
	cout << f1(12, 8) << endl;
	return 0;
}

【仿函数】

包装用法:function<Ret(Args……) 对象名 = 仿函数类()

class Sub
{
public:
	int operator()(int x, int y)
	{
		return (x - y);
	}
};
int main(void)
{
	function<int(int, int)> f2 = Sub();
	return 0;
}

【静态类成员函数指针】

包装方法:function<Ret(Args……) 对象名 = &类域::函数指针

& 可以不加,不影响结果,但是加上要更优一些。

class Sub
{
public:
	static int SubStatic(int x, int y)
	{
		return (x - y);
	}
};
int main(void)
{
	function<int(int, int)> f2 = &Sub::SubStatic;
	cout << f2(10, 3) << endl;
	function<int(int, int)> f3 = Sub::SubStatic;
	cout << f2(10, 3) << endl;
	return 0;
}

【非静态类成员函数指针】

包装方法:function<Ret(类域名, Args……) 对象名 = &类域::函数指针

class Sub
{
public:
	int SubMember(int x, int y)
	{
		return (x - y);
	}
};
int main(void)
{
	function<int(Sub, int, int)> f4 = Sub::SubMember;
	cout << f4(Sub(), 3, 1) << endl;
	return 0;
}

非静态类成员函数指针包装后,使用包装后的对象进行调用,第一个参数,必须是类名。

【lambda表达式】

包装方法:function<Ret(Args……) 对象名 = lambda表达式

int main(void)
{
	function<double(double, double)> f5 = [](double x, double y)mutable->double {return x - y; };
	cout << f5(2.23, 1.11) << endl;
	return 0;
}

bind

bind也是一个包装器。

作用一:调整参数的顺序

普通函数指针的包装方法:function<Ret(Args...)> 对象名 = bind(函数指针,newArgs……)

int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//function、bind包装函数指针
	function<int(int, int)> f1 = Sub;
	//将第一个参数和第二个参数交换
	function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1);
	cout << f1(12, 8) << endl;
	cout << f2(12, 8) << endl;
	return 0;
}

placeholders::_n,表示当前function类中参数包的第n个参数。

希望怎么调整参数的顺序,就在调用bind函数时,传递什么样的参数顺序。bind函数传参时,使用placeholders::_n。

作用二、指定某个参数的值

#include <iostream>
#include <functional>
using namespace std;
int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//function、bind包装函数指针
	function<int(int, int)> f2 = bind(Sub, 10, placeholders::_2);
	cout << f2(12, 8) << endl;
	return 0;
}

使用function和bind包装过后,并且指定了某个参数的值。function实例化的时候可以省略掉指定了值的参数的参数类型。省略掉后要注意维护bind函数内的参数包。

int Sub(int x, int y)
{
	return x - y;
}
int main(void)
{
	//function、bind包装函数指针
	function<int(int)> f2 = bind(Sub, 10, placeholders::_1);
	cout << f2(8) << endl;
	return 0;
}

可得出结论,bind的间接作用:调整参数的个数。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们