Lambda表达式、回调函数、bind()、function()

Lambda表达式、回调函数、std::bind() std::function()

Lambda表达式

相当于匿名函数,不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散.

以以下代码为例解释,demo.cpp:

config.applyMsgCallback = [](const raft::ApplyMessage& msg) {
        assert(msg.command.getStringView() == "raft example");
    };
config.snapshotCallback = [](const json::Value& snapshot) {
        FATAL("not implemented yet");
    };

语法形式

[ c a p t u r e ] ( p a r a m s ) o p t − > r e t { b o d y ; } ; [capture](params)opt->ret\{body;\}; [capture](params)opt>ret{ body;};

  • capture:捕获列表
  • params: 参数表
  • opt: 函数选项
  • ret:返回值类型
  • body: 函数体
    auto func = [](int a)->int{return a+1;};
    std::cout<<func(2)<<"\n";  // output 3

省略返回值类型

auto func = [](int a){return a+1;};
auto x2 = [](){ return { 1, 2 }; };  // error: 无法推导出返回值类型这时我们需要显式给出具体的返回值类型。

没有参数列表,省略参数表

auto func = [](){return 1;};
auto f = []{return 1;}; // 直接省略空的参数列表

捕获列表

  • []不捕获任何变量
  • [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)
  • [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)
  • [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量
  • [bar] 按值捕获 bar 变量,同时不捕获其他变量
  • [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量
// example

class LAM{
public:
    int index = 0;
    void func(int x,int y){
        // auto x1 = []{return index;}; // error 没有捕获外部变量
        auto x2 = [=]{return index + x + y;}; // 捕获所有外部变量
        auto x3 = [&]{return index + x + y;};
        auto x4 = [this]{return index;}; // cathc this pointer
        // auto x5 = [this]{return index+ x+ y;}; // error
        auto x6 = [this,x,y]{return index+x+y;};
        auto x7 = [this]{return index++;}; //修改成员变量
    }
};
int a = 0, b = 1;
auto f1 = []{ return a; };               // error,没有捕获外部变量
auto f2 = [&]{ return a++; };            // OK,捕获所有外部变量,并对a执行自加运算
auto f3 = [=]{ return a; };              // OK,捕获所有外部变量,并返回a
auto f4 = [=]{ return a++; };            // error,a是以复制方式捕获的,无法修改
auto f5 = [a]{ return a + b; };          // error,没有捕获变量b
auto f6 = [a, &b]{ return a + (b++); };  // OK,捕获a和b的引用,并对b做自加运算
auto f7 = [=, &b]{ return a + (b++); };  // OK,捕获所有外部变量和b的引用,并对b做自加运算

延迟调用

int a = 0;
auto f = [=]{ return a; };      // 按值捕获外部变量
a += 1;                         // a被修改了
std::cout << f() << std::endl;  // 输出?

output a = 0; 因为是值捕获

使用mutable 修改值捕获的外部变量的值

int a = 0;
auto f1 = [=]{ return a++; };             // error,修改按值捕获的外部变量
auto f2 = [=]() mutable { return a++; };  // OK,mutable

回调函数

函数指针

深入浅出——理解c/c++函数指针 - 知乎 (zhihu.com)

int foo()
{
    return 5;
}

函数type是int (*somefunction)()

如果是“有两个*整形*参数且返回值是布尔型”的我们可以这么表示bool (*someotherfunction)(int, int)

和变量一样,函数在内存中有固定的地址。函数的实质也是内存中一块固定的空间。

int (*const funcPtr)();
// 另外,对于 
const int(*funcPtr);
// 意思是这个指针指向的函数的返回值是常量
int foo()
{
    
    
    return 5;
}
 
int goo()
{
    
    
    return 6;
}
int (*funcPtr)() = foo;
funcPtr = goo;
  //但是千万不要写成funcPtr = goo();这是把goo的返回值赋值给了funcPtr

通过函数指针调用函数

int foo(int x)
{
    
    
    return x;
}
 
int main()
{
    
    
    int (*funcPtr)(int) = foo; 
    (*funcPtr)(5); // 通过funcPtr调用foo(5)
    funcPtr(5) // 也可以这么使用,在一些古老的编译器上可能不行
    return 0;
}

以参数形式传递函数指针

#include <iostream>
int add(int a, int b){
    
    
    return a+b;
}
int sub(int a, int b){
    
    
    return a-b;
}
void func(int e, int d, int(*f)(int a, int b)){
    
     // 这里才是我想说的,
// 传入了一个int型,双参数,返回值为int的函数
    std::cout<<f(e,d)<<std::endl;
}
int main()
{
    
    
    func(2,3,add);
    func(2,3,sub);

    return 0;
}

callback

回调函数就是一个通过函数指针调用的函数。回调函数,顾名思义,就是使用者自己定义一个函数,使用者自己实现这个函数的程序内容,然后把这个函数作为参数传入别人(或系统)的函数中,由别人(或系统)的函数在运行时来调用的函数。函数是你实现的,但由别人(或系统)的函数在运行时通过参数传递的方式调用,这就是所谓的回调函数。简单来说,就是由别人的函数运行期间来回调你实现的函数。

C++学习之回调函数_c++回调函数_HAH-M的博客-CSDN博客

std::function()

【C++】C++11的std::function和std::bind用法详解_c++ bind 对象成员函数到普通函数_Yngz_Miao的博客-CSDN博客

std::function是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行

std::function的作用可以归结于:

std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的std::function对象,简化调用;
std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(如:函数指针这类可调用实体,是类型不安全的)

所以:

 struct RequestVoteArgs;
    struct RequestVoteReply;
    struct AppendEntriesArgs;
    struct AppendEntriesReply;
    struct ApplyMessage;

    typedef std::function<void( const RequestVoteReply&)> RequestVoteDoneCallback;
    typedef std::function<void( const AppendEntriesReply&)> AppendEntriesDoneCallback;
    typedef std::function<void( const RequestVoteArgs&,
                                const RequestVoteDoneCallback&)> DoRequestVoteCallback;
    typedef std::function<void( const AppendEntriesArgs& args,
                                const AppendEntriesDoneCallback& done)> DoAppendEntriesCallback; 
    typedef std::function<void( int,
                                const RequestVoteArgs&,
                                const RequestVoteReply&)> RequestVoteReplyCallback;
    typedef std::function<void( int,
                                const AppendEntriesArgs&,
                                const AppendEntriesReply&)> AppendEntriesReplyCallback;
    typedef std::function<void( const ApplyMessage&)> ApplyMsgCallback;
    typedef std::function<void( const json::Value&)> SnapshotCallback;

相当于定义了一些函数指针的模板类,也就是回调函数

std::bind()

std::bind可以看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。

std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存。std::bind主要有以下两个作用:

将可调用对象和其参数绑定成一个仿函数;
只绑定部分参数,减少可调用对象传入的参数。

调用bind的一般形式:

auto newCallable = bind(callable, arg_list);

该形式表达的意思是:当调用newCallable时,会调用callable,并传给它arg_list中的参数。

具体例子,注意参数绑定中用的占位符,std::placeholders::_1

int main(int argc, char * argv[]) {
    
    
    //f1的类型为 function<void(int, int, int)>
    auto f1 = std::bind(fun_1, 1, 2, 3); 					//表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
    f1(); 													//print: x=1,y=2,z=3
auto f2 = std::bind(fun_1, std::placeholders::_1, std::placeholders::_2, 3);
//表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别由调用 f2 的第一,二个参数指定
f2(1, 2);												//print: x=1,y=2,z=3
 
auto f3 = std::bind(fun_1, std::placeholders::_2, std::placeholders::_1, 3);
//表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别由调用 f3 的第二,一个参数指定
//注意: f2  和  f3 的区别。
f3(1, 2);												//print: x=2,y=1,z=3

int m = 2;
int n = 3;
auto f4 = std::bind(fun_2, std::placeholders::_1, n); //表示绑定fun_2的第一个参数为n, fun_2的第二个参数由调用f4的第一个参数(_1)指定。
f4(m); 													//print: a=3,b=4
std::cout << "m = " << m << std::endl;					//m=3  说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的,如m
std::cout << "n = " << n << std::endl;					//n=3  说明:bind对于预先绑定的函数参数是通过值传递的,如n

A a;
//f5的类型为 function<void(int, int)>
auto f5 = std::bind(&A::fun_3, &a, std::placeholders::_1, std::placeholders::_2); //使用auto关键字
f5(10, 20);												//调用a.fun_3(10,20),print: k=10,m=20

std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
fc(10, 20);   											//调用a.fun_3(10,20) print: k=10,m=20 

return 0; 

下述代码,就是给回调函数绑定参数列表,然后调用setRequestVoteReplyCallback的话,传参,然后执行OnRequestVoteReply。

for(auto peer : rawPeers){
        peer->setRequestVoteReplyCallback(std::bind(&Node::OnRequestVoteReply,this,_1,_2,_3));
        peer->setAppendEntriesReplyCallback(std::bind(&Node::OnAppendEntriesReply,this,_1,_2,_3));
    }
    raftService.setDoRequestVoteCallback(std::bind(&Node::RequestVote,this,_1,_2));
    raftService.setDoAppendEntriesCallback(std::bind(&Node::AppendEntries,this,_1,_2));

猜你喜欢

转载自blog.csdn.net/qq_47865838/article/details/129914900