【问题标题】:C++ lambda has a different type when it captures variableC ++ lambda在捕获变量时具有不同的类型
【发布时间】:2019-12-26 00:07:03
【问题描述】:

我正在尝试返回一个 lambda 函数,该函数从当前范围内捕获一个变量。当我不捕获变量时,返回lambda函数,可以毫无问题地执行:

#include <iostream>

typedef void(*VoidLambda)();

VoidLambda get() {
    VoidLambda vl = []() {
        std::cout << "hello" << std::endl;
    };
    return vl;
};

int main()
{
    get()(); //prints "hello" as expected
    return 0;
}

如果vl 试图捕获一个变量,编译器将不再编译它:

#include <iostream>

typedef void(*VoidLambda)();

VoidLambda get(const char* x) {
    VoidLambda vl = [x]() { //Error: no suitable conversion function from "lambda []void ()->void" to "VoidLambda" exists
        std::cout << x << std::endl;
    };
    return vl;
};

int main()
{
    get("hello")();
    return 0;
}

我已经尝试将第二个 lambda 转换为 VoidLambda,但问题仍然存在。

我想知道第一个和第二个 lambda 表达式有什么区别,以及如何解决问题(即返回带有捕获的 lambda 函数)。

【问题讨论】:

  • 每个 Lamba 都有一个唯一的(特定于实现的)类型。因此,期望任何两个 lambda 具有相同的类型,即使它们具有相同的捕获和参数列表,也是毫无意义的。如果您想使用命名类型传递 lambda,您的代码需要使用模板、自动类型推导或模板化帮助器(例如 std::function)的某种组合。

标签: c++ lambda


【解决方案1】:

不捕获任何状态的 Lambda 函数是无状态的。因此,可以将它们建模为普通函数。如果他们需要捕获不再正确的状态:状态需要在某个地方并且函数指针没有用于状态的位置。

基本上有两种选择:

  1. 使用推导类型返回 lambda 函数,例如:

    auto get(char* x) { return [x]{ std::cout << x << "\n";  }; }
    
  2. 返回 lambda 函数的类型擦除表示:

    std::function<void()> get(char* x) { return [x]{ std::cout << x << "\n"; }; }
    

选择哪一个取决于您的需求。第二个在概念上更接近函数指针。第一个更高效,但要求函数为inline(或至少在使用时可见)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    相关资源
    最近更新 更多