如何在类外部定义Lambda函数并在C ++中的类内部使用它?

时间:2018-09-13 13:31:04

标签: c++ lambda

我想做这样的事情:

// define a lambda to be called from some class method
auto state_0_stuff = [&](){
    .
    caller_data.some_func();  <-- identifier undefined compiler error
    .
}

// call the lambda from some class method, capturing the data and using in the lambda.
void foo::some_func(){
    int state = 0;
    bool done = false;
    // more data...
    bar caller_data;

    while(!done){
        switch(state){
        case 0:
           state_0_stuff();       <-- instead of adding lots of code here, call lambda
           state = 1;
           break;
        case 1:
           done = true;
           break;
        }
    }
}

如果我在foo :: some_func主体中定义lambda,这将起作用,但如果我尝试在外部定义lambda,则不会。

是否有一些相对简单的语法可以达到这种效果?

我不在乎是否使用lambda,这只是我的第一个主意。目的是简化switch(state)的内容,以使代码比在情况下添加50行内容的代码更具可读性。

很明显,我可以使用正常的函数,并来回传递一堆东西,但是如果像Lambda那样仅由函数捕获本地状态,那就不会那么复杂了。

2 个答案:

答案 0 :(得分:4)

没有任何方法可以隐式捕获Lambda中超出对象范围的对象。您需要明确地传递它们。

作为解决方案,您可以向private添加foo成员函数,然后调用该函数:

void foo::case0(bar& caller_data, /* ... */) 
{
    lots_of_calcs_that_reference_caller_data();
    .
    caller_data.some_func();
    .
}

void foo::some_func(){
    int state = 0;
    bool done = false;
    // more data...
    bar caller_data;

    while(!done){
        switch(state){
        case 0:
           case0(caller_data, /* ... */);
           state = 1;
           break;
        case 1:
           done = true;
           break;
        }
    }
}

否则,您可以使用重载的struct创建一个operator()并在其构造函数中传递“捕获”。

答案 1 :(得分:3)

lambda捕获声明状态的状态。所以当你有

auto state_0_stuff = [&](){
    lots_of_calcs_that_reference_caller_data();
    .
    caller_data.some_func();
    .
}
全局空间[&]中的

仅捕获该空间中可用的内容。当您在函数中调用lambda时,它将使用捕获的状态,而不是函数的当前状态。

您将不得不在函数中声明lambda或编写将状态传递给的函数/函数。您还可以将其设为类的私有成员函数,以便它可以访问类状态,而只需将所需的任何函数本地状态传递给它。


关于声明lambda时会发生什么的更深入的研究:

这样做的时候

auto foo = [&](){ your code here };

编译将其扩展为类似(非常简化)的内容:

struct some_compiler_generate_name
{
    some_compiler_generate_name(list of captured variables) : initialize captured variables {}
    operator () const { your code here  }
private:
    captured variables;
} foo(list of variables to capture);

因此您可以看到我们在声明时就创建了lambda对象,并且由于此操作,它会用它可能具有的所有捕获变量进行初始化。您无法重新捕获变量,因为您无法再次调用其构造函数。