C++11相较于C++98 标准新增内容:包装器

包装器

function

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

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

现在我们有一个函数模板

1   template<class F, class T>
2   T useF(F f, T x)
3   {
4  		static int count = 0;
5  	  	cout << "count:" << &count << endl;
6     	return f(x);
7   }

对于函数模板,编译器会根据实参,按照模板定义出一份特定的函数。
函数内部的静态成员变量是属于函数的,无论调用多少次该函数,都只会定义出一个。
记住上面这两个知识点,现在增加一个函数和仿函数,用来测试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的间接作用:调整参数的个数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小酥诶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值