C++可调用对象

本文深入探讨了C++中的可调用对象,包括普通函数、函数指针、类成员函数、类静态函数、仿函数和lambda表达式,并介绍了C++11新特性std::function的使用,它能兼容多种类型的可调用对象。此外,还讨论了std::bind函数适配器在参数绑定中的应用。最后,提到了这些可调用对象在多线程场景中的运用,如std::thread、std::async和std::call_once。
摘要由CSDN通过智能技术生成

一、C++中的各种可调用对象

1、普通函数

int AddFun(const int a, const int b)
{
	return a + b;
}

2、函数指针

// 声明一个compute函数指针,函数参数为两个int型,返回值为int型
typedef int(*compute)(int, int);

int max(int x, int y) { return x >= y ? x : y; }
int min(int x, int y) { return x <= y ? x : y; }

// 一个包含函数指针作为回调的函数
int compute_x_y(int x, int y, compute fc) { return fc(x, y); }

int main(void)
{
	int x = 2, y = 5;
	std::cout << "max: " << compute_x_y(x, y, max) << std::endl; // max: 5
	std::cout << "min: " << compute_x_y(x, y, min) << std::endl; // min: 2

	// 无捕获的lambda可以转换为同类型的函数指针
	auto sum_lambda = [](int x, int y)->int { return x + y; };
	std::cout << "sum_lambda: " << compute_x_y(x, y, sum_lambda) << std::endl; // sum_lambda: 7
	return 0;
}

3、类成员函数、类静态函数、仿函数

class Complex
{
private:
	double re, im;

public:
	//支持类型转换的构造
	Complex(const double r = 0, const double i = 0)
		:re(r), im(i)
	{
		std::cout << this << std::endl;
	}

	// 类的成员方法,参数包含this指针
	double distance(const double Com_x, const double Com_y)
	{
		return sqrt(pow(this->re - Com_x, 2) + pow(this->im - Com_y, 2));
	}

	//类的静态成员方法,不包含this指针
	static int AddFun(const int a, const int b) { return a + b; };

	//仿函数
	double operator()() const
	{
		return sqrt(pow(this->re, 2) + pow(this->im, 2));
	}
};

4、lambda表达式( C++11新特性)
形式:
[captures] (params) -> return_type { statments;}

其中:

  1. [captures]为捕获列表,用于捕获外层变量
  2. (params)为匿名函数参数列表
  3. ->return_type指定匿名函数返回值类型
  4. { statments; }部分为函数体,包括一系列语句

说明:
当匿名函数没有参数时,可以省略(params)部分
当匿名函数体的返回值只有一个类型或者返回值为void时,可以省略->return_type部分
定义匿名函数时,一般使用auto作为匿名函数类型

auto func1 = [](int x, int y) -> int { return x + y; }; 
auto func2 = [](int x, int y) { return x > y; }; // 省略返回值类型
auto func3 = [] { global_ip = 0; }; // 省略参数部分
//......等

重点:
为了能够在Lambda函数中使用外部作用域中的变量,需要在[]中指定使用哪些变量。

  1. [] 不捕获任何变量
  2. [&] 捕获外部作用域中所有变量,并作为引用在匿名函数体中使用
  3. [=] 捕获外部作用域中所有变量,并拷贝一份在匿名函数体中使用
  4. [x, &y] x按值捕获, y按引用捕获
  5. [&, x] x按值捕获其它变量按引用捕获
  6. [=, &y] y按引用捕获. 其它变量按值捕获
  7. **[this]**捕获当前类中的this指针,如果已经使用了&或者=就默认添加此选项

注意:
只有lambda函数没有指定任何捕获时,才可以显式转换成一个具有相同声明形式函数指针
如“2、函数指针”中的源代码所示。

二、对可调用对象的封装和通用的函数适配器

1、std::function( C++11新特性)

  1. 类模板std :: function是一个通用的多态函数包装器
  2. 够兼容所有具有相同参数类型的函数实体,包括类成员函数
  3. 能兼容带捕获lambda表达式,而函数指针不能
  4. 需要#include < functional >
  5. std命名空间
int main(void)
{
	//接上文main上部分内容
	std::function<int(int, int)> Function;
	// 普通函数
	Function = AddFun;
	std::cout << "AddFun: " << Function(x, y) << std::endl; // AddFun: 7

	// 函数指针
	compute fc = max;
	Function = fc;
	std::cout << "function pointer: " << Function(x, y) << std::endl; // lambda: 5

	//类的成员方法
	Complex comp(x, y);
	std::function<double(double, double)> Func1= std::bind(&Complex::distance, comp,
		std::placeholders::_1, std::placeholders::_2); // 绑定this对象
	std::cout << "distance: " << Func1(y, x) << std::endl;		// distance: 4.24264

	// 类静态函数
	Function = Complex::AddFun;
	std::cout << "AddFun: " << Function(x, y) << std::endl; // AddFun: 7

		// 仿函数
	std::function<double()> Func2 = comp;
	std::cout << "func:" << Func2() << std::endl;	//func:5.38516

	// lambda函数
	Function = sum_lambda;
	std::cout << "lambda: " << Function(x, y) << std::endl; // lambda: 7

	// 带捕获的lambda函数
	int data = 10;
	auto sum_lambda_capture = [&data](int x, int y)->int {data = data + x + y; return data; };
	Function = sum_lambda_capture;
	std::cout << "lambda capture: " << Function(x, y) << std::endl;	//lambda capture: 17
	std::cout << "capture value: " << data << std::endl; // capture value: 17
	return 0;
}

拓展:关于回调函数
回调就是通过把函数等作为另外一个函数的参数的形式,在调用者层指定被调用者行为的方式。
可以使用函数指针,以及std::function作为函数参数类型

2、std::bind通用的函数适配器
参数绑定规则
a)std::bind绑定类成员函数

std::function<double(double, double)> Func1= std::bind(&Complex::distance, comp,
		std::placeholders::_1, std::placeholders::_2); // 绑定this对象
  1. 第一个参数为类成员函数名的引用(推荐使用引用,实现多态)
  2. 第二个参数为this指针上下文,即特定的对象实例
  3. 之后的参数与类成员函数定义顺序一一对应,可用std::placeholders::_n占位符,也可直接传参
  4. std::placeholders::_n表示调用时的第n个参数

b)std::bind绑定非类成员可调用对象
出来使用占位符,调换调用时参数绑定顺序外,并无太多用途,不建议使用。可将非类成员可调用对象直接赋值给函数指针或者function对象。

警告: 请不要在构造函数中将this参数传出,因为这是该对象是个半成品。

三、对可调用对象在多线程中的使用

1、thread类,async、call_once函数模板
参见:
thread类:C++11标准库thread构造函数浅析中的三、1
async函数模板:C++11多线程标准库进阶中的一、1
call_once函数模板:C++11标准库之锁中的五、6

一个参数为可调用对象,还有一个参数为不定个数的参数列(C++11新特性:Variadic Templates(…))

2、condition_variable

//condition_variable类的成员函数
template<class _Predicate>
	void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
	{	// wait for signal and test predicate
	while (!_Pred())
		wait(_Lck);
	}

_Pred只能是返回值为bool或者隐士转换为bool,参数为空的可调用对象(普通函数、函数指针、仿函数、类的静态函数和function对象)

3、packaged_task模板类
参见:
C++11多线程标准库进阶中的五

//其中一个构造函数
template<class _Fty2,
		class _Alloc>
		explicit packaged_task(allocator_arg_t, const _Alloc& _Al,
			_Fty2&& _Fnarg)
		: _MyPromise(_Make_packaged_state<_Ret(_ArgTypes...)>(
			_STD forward<_Fty2>(_Fnarg)), _Al)
		{	// construct from rvalue function object and allocator
		}

第三参数_Fnarg为可调用对象,传function对象,或者用bind适配成一个function对象,

如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大胡子的艾娃

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

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

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

打赏作者

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

抵扣说明:

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

余额充值