C++11 lambda 返回 lambda

标签 c++ visual-c++ lambda c++11 visual-studio-2012

这段代码对于 JS 开发者来说并不陌生

function get_counter()
{
    return (
        function() {
            var c = 0;
            return function() { return ++c; };
        })();
}

它基本上创建了一个创建不同枚举数的。所以我想知道是否可以在 C++11 中使用新的 lambda 语义来完成同样的事情?我最终写了这段 C++ 不幸的是不能编译!

int main()
{
    int c;
    auto a = [](){
        int c = 0;
        return [&](){
            cout << c++;
        };
    };
    return 0;
}

所以我想知道是否有一种解决方法来编译它,以及编译器如何使这段代码正确运行?我的意思是它必须创建单独的枚举器,但它也应该收集垃圾(未使用的 c 变量)。

顺便说一句,我使用的是 VS2012 编译器,它会产生这个错误:

Error   2   error C2440: 'return' : cannot convert from 'main::<lambda_10d109c73135f5c106ecbfa8ff6f4b6b>::()::<lambda_019decbc8d6cd29488ffec96883efe2a>' to 'void (__cdecl *)(void)'    c:\users\ali\documents\visual studio 2012\projects\test\test\main.cpp   25  1   Test

最佳答案

您的代码有一个错误,它包含一个悬空引用; c 引用将引用外部 lambda 中的局部变量,当外部 lambda 返回时,该局部变量将被销毁。

您应该使用 mutable 按值 lambda 捕获来编写它:

auto a = []() {
    int c = 0;
    return [=]() mutable {
        cout << c++;
    };
};

这依赖于后标准扩展,以允许在返回类型推导 lambda 中使用多个语句; Is there a reason on not allowing lambdas to deduce the return type if it contains more than one statement?修复它的最简单方法是提供一个参数,使 lambda 只包含一条语句:

auto a = [](int c) {
    return [=]() mutable {
        cout << c++;
    };
};

不幸的是,lambdas 中不允许使用默认参数,因此您必须将其称为 a(0)。或者以可读性为代价,您可以使用嵌套的 lambda 调用:

auto a = []() {
    return ([](int c) {
        return [=]() mutable {
            cout << c++;
        };
    })(0);
};

其工作方式是,当 a 执行内部 lambda 时,会将所有引用的变量复制到其闭包类型的实例中,如下所示:

struct inner_lambda {
    int c;
    void operator()() { cout << c++; }
};

闭包类型的实例随后由外部 lambda 返回,并且可以被调用并在调用时修改它的 c 拷贝。

总体而言,您的(固定)代码被翻译为:

struct outer_lambda {
    // no closure
    struct inner_lambda {
        int c;    // by-value capture
        // non-const because "mutable"
        void operator()() { cout << c++; }
    }
    // const because non-"mutable"
    inner_lambda operator()(int c) const {
        return inner_lambda{c};
    }
};

如果您将 c 作为按引用捕获,则为:

struct outer_lambda {
    // no closure
    struct inner_lambda {
        int &c;    // by-reference capture
        void operator()() const { cout << c++; } // const, but can modify c
    }
    inner_lambda operator()(int c) const {
        return inner_lambda{c};
    }
};

这里的inner_lambda::c是对局部参数变量c的悬空引用。

关于C++11 lambda 返回 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12639578/

相关文章:

c++ - 如何找到数组的长度?

.net - SHCreateStreamOnFileEx 链接器错误

c++ - Visual Studio 找不到任何标准 C++ 库文件

c# - 用于重构安全 ArgumentException 的 Lambda 表达式

lambda - Java 8 流和 lambda 是在骗人吗?

C++ 语义问题 : "' use of undeclared identifier 'balance' "

C++:传递具有任意数量参数的函数作为参数

c++ - 使用 boost 创建一个始终返回 true 的 lambda 函数

c++ - 线程安全内存池

c++ - Windows Xp - 无法找到入口点 gettickcount64 kernel32.dll