无法通过移动传递已删除的 lambda 函数?

cannot pass deleted lambda function with move?

我有以下 lambda 表达式:

    auto pPerson = std::make_unique<Person>("Person");
    
    auto personLambda = [=, persPointer = std::move(pPerson)](int x, int y) mutable
    {
        //do stuff
    };

    acceptLambda(myVector, personLambda);//compiler error

acceptLambda():

template<typename Func>
void acceptLambda(std::vector<int> myVector, Func f) {
//do stuff
}

错误:

function "lambda []std::string (int c, int y) mutable->std::string<unnamed>(const lambda []std::string (int x, int y) mutable->std::string &)" (declared implicitly) cannot be referenced -- it is a deleted function

如上所述,我 运行 遇到编译器错误,告诉我无法将此 lambda 传递给 acceptLamba() 函数。我上面还有其他 lambda 可以正常工作;当我传入 personLambda 时(在捕获子句中包含 std::move),一切都崩溃了。

当我删除 unique_ptr 上的移动操作时,一切都按预期进行。但是,我想将此 unique_ptr 移动到 lambda 中以便在并发环境中使用并避免悬空指针情况。

为什么std::move操作会导致这个错误?如何解决这个问题?

让我们从错误消息开始:

function "lambda []std::string (int c, int y) mutable->std::string<unnamed>(const lambda []std::string (int x, int y) mutable->std::string &)" (declared implicitly) cannot be referenced -- it is a deleted function

那是一口。如果您认识到 lambda []std::string (int c, int y) mutable->std::string 是您的 lambda 类型的名称(显然它的 return 语句导致 auto 被推断为 std::string),则更容易理解。让我们调用该类型 L 并查看消息的样子。

function "L(const L &)" (declared implicitly) cannot be referenced -- it is a deleted function

你的 lambda 的复制构造函数被隐式删除。这应该是有道理的,因为您的 lambda 捕获了一个不可复制的值(unique_ptr)。然而,当您将 personLambda 按值 传递给 acceptLambda 时,您尝试制作副本。这不起作用。

完整的错误消息可能包含更多信息,可以帮助您了解无法复制 lambda 的原因。在 error 行之后可能有一些 note 行解释说 unique_ptr 不能被复制。但是,当使用 IDE,例如 Visual Studio 时,您可能必须从摘要编译器输出选项卡切换到完整编译器输出选项卡才能看到它。

选项 1
您也许可以通过引用 传递 lambda 。可能。也许你确实需要一个更大的方案的副本,但如果你不需要,那么 acceptLambda 可以通过引用获取它的第二个参数(并且可能应该通过 const 引用获取第一个参数)。

void acceptLambda(const std::vector<int> & myVector, Func & f) 
//                                                        ^-- by reference

选项 2
您可以像解决无法复制 unique_ptr 一样解决无法复制 lambda 的问题。你可以移动它。请注意,在调用 acceptLambda 后,personLambda 将无法使用。 (如果这是一个问题,您可能应该使用 shared_ptr 而不是 unique_ptr。)

acceptLambda(myVector, std::move(personLambda));
//                     ^^^^^^^^^^            ^