广州网站设计公司排名,网站建设的广告语,宣传册设计与制作免费,腾讯云服务器用什么软件做网站std::function与可调用对象 函数指针lambda表达式std::function与std::bind仿函数总结std::thread与可调用对象std::async与可调用对象回调函数 可调用对象是指那些像函数一样可以直接被调用的对象#xff0c;他们广泛用于C的算法#xff0c;回调#xff0c;事件处理等机制。… std::function与可调用对象 函数指针lambda表达式std::function与std::bind仿函数总结std::thread与可调用对象std::async与可调用对象回调函数 可调用对象是指那些像函数一样可以直接被调用的对象他们广泛用于C的算法回调事件处理等机制。
函数指针
函数指针是最简单的一种可调用对象
我们大家应该都用过函数名来作为函数的地址但是函数名称其实与函数的地址是有一些细微的差别的
void printHello() {std::cout Hello, World! std::endl;
}以上面的函数为例函数的名称是printHello, 但是它的类型其实是void() , 而不是void(*)但是它可以被隐式的转化成void( *
void (*ptr)() printHello;在上面这行代码中printHello会被隐式转化为void( * )(), 这就跟char [] 能被隐式的转化为char *很类似
如下代码也能完成上述转化但是是显示的取函数地址
void (*ptr)() printHello显示利用运算符取地址
言归正传在得到函数指针之后我们就可以直接通过函数指针调用函数并且可以将其作为一些函数的参数
例如
bool cmp( int a, int b)
{return a b;
}std::vectorint vec {2,1,4,3,7,6};
std::sort(vec.begin(),vec.end(),cmp);上述例子就会将容器vec中的元素从小到大进行一个排序了。
lambda表达式
lambda是C11引入的一种匿名函数对象提供了一种简单的方式用来定义内联函数它的标准格式如下
[capture-list] (parameters) - return-type { body }[capture-list] 捕获列表捕获的变量可以在lambda表达式的函数体内使用 (parameters) 参数列表与函数的参数列表一致 - return-type 返回值如果不写lambda表达式会自动推导返回值 {body} 函数体
既然返回值可以省略lambda表达式最常见的格式就是
[](){}其中
[x] 表示用引用的方式捕获变量x[x] 表示用值捕获的方式捕获变量x[] 按值捕获的方式捕获作用域内所有变量[] 按引用捕获的方式捕获作用域内所有变量[a, b] 按值捕获a, 按引用捕获blambda表达式最简单的使用方式:
auto lambda [](){std::cout Hello World std::endl;
};
lambda();int x 5;
auto lambda [x](int a){return x a;
};
lambda(6);如上图两个例子所示lambda表达式可以就像普通函数那样被调用
lambda表达式的类型
auto lambda [](){std::cout Hello World std::endl;
};你知道此时auto是什么类型吗
编译器会为每一个lambda表达式生成如下面所示的一个类
class __lambda_1 {
public:void operator()() const {std::cout Hello, Lambda! std::endl;}
};这个类是使用了operator重载了()运算符的一个类听起来跟隐函数非常像此时auto的类型就是 __lambda_1
同样lambda表达式也可以带入到各种以可调用对象为参数的函数之中
auto lambda [](int x,int y){return x y;
};std::vectorint vec {2,3,1,7,6,5};
std::sort(vec.begin(),vec.end(), lambda);std::function与std::bind
std::funtion也是一个可调用对象它本质上叫做泛型函数包装器可以用来包装任何的可调用对象只要这个可调用对象的调用签名与自己匹配即可。 也可以用来包装另一个std::funtion因为function也是一个可调用对象
什么是调用签名
std::functionint(int,int) func ;上面定义了一个调用签名为 int (int,int)的function对象表示这个function只能用来包装返回值为int,参数为(int,int)的可调用对象
绑定普通函数-无参数
void printHello() {std::cout Hello, World! std::endl;
}std::functionvoid() func printHello;
func();绑定lambda表达式
auto lambda [](){std::cout Hello World std::endl;
};
std::functionvoid() func lambda
func();绑定仿函数
class PrintFunctor {
public:void operator()() const {std::cout Hello from functor! std::endl;}
};PrintFunctor functor;
std::functionvoid() func functor;
func();
-----------------------------------------------------
int add(int a,int b)
{return a b;
}class PrintFunctor {
public:int operator()(int x) const {return add(x,2);}
};
PrintFunctor functor;
std::functionint(int) func functor;
func(1);绑定另一个function
void printHello() {std::cout Hello, World! std::endl;
}
std::functionvoid() func1 printHello;
std::functionvoid() func2 func1;绑定普通函数-带参数
int add(int a,int b)
{return a b;
}std::functionint(int,int) func add;
int res func(1,2);以上是一些实用std::function的最简单的例子但是function还远不止于此如果我们想让绑定更加灵活呢例如我们想绑定上面的add函数但是其中一个参数是已经确定的如何绑定呢 这时候就需要用到std::bind
std::bind是用来生成std::function的一个函数能让std::function的包装更加灵活, 他可以将所有的可调用对象包装成std::function
std::bind绑定普通函数
int add(int a,int b)
{return a b ;
}
--------------------------------------------------------固定参数绑定
std::functionint() func std::bind(add,1,2);
func(); //调用
--------------------------------------------------------不定参数绑定
std::functionint(int) func std::bind(add,1,std::placeholders::_1);
func(2); //调用std::functionint(int,int) func std::bind(add,std::placeholders::_1,std::placeholders::_2);
func(1,2);//调用其中
std::placeholders::_1表示参数_1后缀表示第一个不定参数如果想绑定多个不定参数只需要让后缀继续加就行
std::bind绑定类成员函数
class MyClass {
public:int add(int x, int y) {return x y;}
};MyClass myclass;
std::functionint(int,int) func std::bind(MyClass:add,myclass,add,std::placeholders::_1,std::placeholders::_2);
func(1,2); //调用绑定lambda表达式
std::functionint(int,int) func std::bind([](int x,int y){return x y;},std::placeholders::_1std::placeholders::_2);func(1,2); //调用绑定std::function(套娃
int add(int a,int b)
{return a b ;
}
std::functionint(int,int) func std::bind(add,std::placeholders::_1,std::placeholders::_2);
std::functionint(int) func1 std::bind(func1,1,std::placeholders::_1);
func1(2);绑定仿函数
class ADDFunctor { //
public:int operator()(int x) const {return add(x,2);}
};
ADDFunctor functor;
std::functionint(int) func std::bind(functor,std::placeholders::_1);
func(1);上面介绍了这么多其实都一样只要是可调用对象绑定的方式都相同只有类成员函数的绑定方式要特殊一些需要指定对象。
同样std::function也可以带入到std::sort中作为比较子
std::functioniint(int,int) func std::bind([](int x,int y){return x y;},std::placeholders::_1std::placeholders::_2);std::vectorint vec {5,2,3,7,1,4};std::sort(vec.begin(),vec.end(),func);---------------------------------------------std::sort(vec.begin(),vec.end(),std::bind([](int x,int y){return x y;
},std::placeholders::_1,std::placeholders::_2)); //lambda表达式比较多余这里直接用lambda表达式就行
//仅用来展示语法在使用std::bind绑定时经常要用到std::placeholders::_1这就会导致单行代码过于长为了处理好看的问题经常使用宏定义的方式处理。
#define PHS std::placeholders// 绑定普通函数(当然也可以用于绑定其他可调用对象
#define BIND_FUNC_0(_f) std::bind(_f)
#define BIND_FUNC_1(_f) std::bind(_f, PHS::_1)
#define BIND_FUNC_2(_f) std::bind(_f, PHS::_2)//绑定类成员函数
#define BIND_CLASS_FUNC_0(_c, _f, _p) std::bind(_c::_f, _p)
#define BIND_CLASS_FUNC_1(_c, _f, _p) std::bind(_c::_f, _p, PHS::_1)
#define BIND_CLASS_FUNC_2(_c, _f, _p) std::bind(_c::_f, _p, PHS::_1,PHS::_2)BIND_FUNC_0 表示绑定一个参数为0的可调用对象 _f表示函数名称 BIND_FUNC_1 表示绑定一个参数为1的可调用对象以此类推
BIND_CLASS_FUNC_0 表示绑定一个参数为0的类成员函数_c表示类名_f表示函数名_p表示对象名称
仿函数
仿函数就是使用 operator重载了()运算符的类
class PrintFunctor {
public:int operator()(int x) const {return add(x,2);}
};
PrintFunctor functor;
functor(1);一个类在重载了()运算符之后就可以像函数那样被直接调用但是它本质上又不是函数所以吧叫做仿函数
class Functor {
public:int operator()(int x, int y) const {return x y;}
};
Functor functor;
std::vectorint vec {5,2,3,7,1,4};
std::sort(vec.begin(),vec.end(), functor);总结
除了上述std::sort的例子以外还有一些用到可调用对象的函数
std::thread与可调用对象
普通函数
void Run(int x, int y, int z)
{.......
}std::thread t(Run,1,2,3);类成员函数
class Myclass{public:void Run(int x,int y,int z){..........}
};
MyClass myclass;
std::thread t(Myclass::Run,myclass,1,2,3);lambda表达式std::function, 仿函数绑定方式也都和普通函数一样
auto lambda [](int x,int y,int z){};
std::thread t(lambda,1,2,3);
----------------------------------------------
std::functionvoid(int,int,int) func std::bind(lambda, std::placeholders::_1std::placeholders::_2, std::placeholders::_3);
std::thread t(func,1,2,3);
----------------------------------------------
class Myclass{public:void Run(int x,int y, int z){.............}
};
MyClass myclass;
std::thread t(myclass,1,2,3);std::async与可调用对象
绑定std::function其余就不展示了因为都一样
void Run(int x)
{.............
}
std::functionvoid(int) func std::bind(Run,std::placeholders::_1);
std::async(std::launch::async, func10); //开启一个异步任务绑定类成员函数
class Myclass{public:void Run(int x,int y,int z){..........}
};
MyClass myclass;
std::async(std::launch::async,Myclass::Run,myclass,1,2,3);回调函数
除了上面的例子之外可调用对象还经常作为回调函数使用
什么是回调函数
回调函数就是将一个可调用对象通过函数或以其它方式传递过去并存储起来然后在合适的时机被调用通常是在某些事件发生之后被调用例如在网络通信中收到消息事件如收到其他套接字发送来的消息也或是在MQRPC通信时收到消息时被调用。
下面举一个简单的例子
class Base
{
public: virtual void Notify(){};
};class Base1
{public:virtual void SetFunc(std::functionvoid() func){};
};class Derivedpulibc Base, pulibc Base1
{public:Derive(){};void Notify(); //通常是某个事件的触发函数例如收到某些信息时触发读到某些数据时被调用触发void SetFunc(std::functionvoid() func);//设置std::functionprivate:std::functionvoid() func_;}void Derived::Notify()
{// ..........// 对接受/读取的数据进行处理 .......//执行回调函数if(func_){func_();}
}void Derived::SetFunc(std::functionvoid() func)
{func_ func;
}Base1* base1 new Derived();void PrintReceive()
{std::cout receive data! std::endl;
}
std::functionvoid() func PrintReceive;base1-SetFunc(func);
Base* base base1;//base指针也可能被传递给其他对象在其他对象内部使用当收到消息时base指针的Notify函数被调用
//在Notify函数中触发了我们的回调函数实现了当收到数据时打印收到数据的日志。