C++;使用 lambdas 在 class 中有条件地扩展一个函数(MWE 的段错误)

C++; using lambdas to conditionally expand a function within a class (seg fault with MWE)

我想使用 lambda 有条件地扩展 class 中函数的功能。在 class 范围之外执行此操作没有问题(参见示例),但下面的最小工作示例在调用在 class 内修改自身的函数时会导致分段错误。谁能解释为什么这段代码会失败,以及我应该如何看待 class 内的 lambda 与 class 外的 lambda?

#include <functional>
#include <iostream>

class MyClass 
{
  public:
    MyClass(bool modify);
    int a;
    std::function<void (void)> myFunc;
};

MyClass::MyClass(bool modify) 
{
    a = 2;
    myFunc = [this](){ std::cout << "1. Inside my initialized function; a=" 
                                 << this->a << std::endl;};
    //myFunc(); -- works with or without being commented
    if (modify)
    {
        myFunc = [this](){ this->myFunc(); 
                           std::cout << "2. adding an output line to my "
                                     << "initialized function" << std::endl;};
        //EDIT: Originally tried
        //       myFunc = [myFunc](){ myFunc(); std::cout << endl; };
        //       but this will not compile.  See edit of post below
        //myFunc(); -- fails with or without being commented
    }
}

int main(int argc, char **argv) 
{
    std::function<void (void)> func;
    int a = 2;
    func = [a](){ std::cout << "1. Inside my initialized function; a=" 
                            << a << std::endl;};
    func = [func](){ func(); 
                     std::cout << "2. adding an output line to my initialized "
                               << "function" << std::endl;};
    std::cout << "Result of modified function outside of class: " << std::endl;
    func();
    std::cout << std::endl;

    std::cout << "Result of unmodified function in class: " << std::endl;
    MyClass myClassNoMod(false);
    myClassNoMod.myFunc();
    std::cout << std::endl;

    std::cout << "Result of modified function in class: " << std::endl;
    MyClass myClassMod(true);
    myClassMod.myFunc();

    return 0;
}

编辑 PaulR在myFunc的更新中给出了捕获myFunc而不是this的合理建议。在我最初的实现中,这是我尝试过的:

myFunc = [myFunc](){myFunc(); std::out << "stuff\n"; };

但这会导致编译器错误

error: 'myFunc' in capture list does not name a variable
        myFunc = [myFunc](){ myFunc();
                  ^
error: 'this' cannot be implicitly captured in this context
        myFunc = [myFunc](){ myFunc();

在您的 class 中,您捕获 this 指针而不是 myFunc 的先前值,因此您的 lambda 将永远递归调用自身,因为在调用时 myFunc 成员将已更改为新的 lambda。

main 中,您按值捕获了 func 的先前值,因此它会按照您的预期进行。

所以我建议按值(即不带 &)捕获 myFunc 的副本,而不是 this

if (modify)
{
    auto previousFunc = std::move(myFunc);
    myFunc = [previousFunc](){ previousFunc(); 
                       std::cout << "2. adding an output line to my "
                                 << "initialized function" << std::endl;};
}

如果您使用的是 C++14 或更新版本,您还可以使用 lambda capture expressions 来避免复制并直接将之前的函数移动到 lambda 捕获中:

if (modify)
{
    myFunc = [previousFunc{std::move(myFunc)}](){ previousFunc(); 
                       std::cout << "2. adding an output line to my "
                                 << "initialized function" << std::endl;};
}