一、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;}
其中:
- [captures]为捕获列表,用于捕获外层变量
- (params)为匿名函数参数列表
- ->return_type指定匿名函数返回值类型
- { 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函数中使用外部作用域中的变量,需要在[]中指定使用哪些变量。
- [] 不捕获任何变量
- [&] 捕获外部作用域中所有变量,并作为引用在匿名函数体中使用
- [=] 捕获外部作用域中所有变量,并拷贝一份在匿名函数体中使用
- [x, &y] x按值捕获, y按引用捕获
- [&, x] x按值捕获其它变量按引用捕获
- [=, &y] y按引用捕获. 其它变量按值捕获
- **[this]**捕获当前类中的this指针,如果已经使用了&或者=就默认添加此选项
注意:
只有lambda函数没有指定任何捕获时,才可以显式转换成一个具有相同声明形式函数指针
如“2、函数指针”中的源代码所示。
二、对可调用对象的封装和通用的函数适配器
1、std::function( C++11新特性)
- 类模板std :: function是一个通用的多态函数包装器
- 够兼容所有具有相同参数类型的函数实体,包括类成员函数
- 能兼容带捕获lambda表达式,而函数指针不能
- 需要#include < functional >
- 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对象
- 第一个参数为类成员函数名的引用(推荐使用引用,实现多态)
- 第二个参数为this指针上下文,即特定的对象实例
- 之后的参数与类成员函数定义顺序一一对应,可用std::placeholders::_n占位符,也可直接传参
- 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