C++ lambda has a different type when it captures v

2020-03-30 02:25发布

问题:

I'm trying to return a lambda function which captures a variable from its current scope. When I don't capture a variable, the lambda function is returned and can be executed with no problem:

#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;
}

If vl attempts to capture a variable, the compiler won't compile it anymore:

#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;
}

I have already tried casting the second lambda to VoidLambda, but the problem remains the same.

I'd like to know what the difference between the first and second lambda expression is, and how to solve the problem (i.e. return the lambda function with captures).

回答1:

Lambda functions which don't capture any state are, well, stateless. Thus, it is possible to model them as a normal function. If they need to capture state that isn't true anymore: the state needs to somewhere and function pointer doesn't have a place for the state.

There are basically two alternatives:

  1. Return the lambda function using a deduced type, e.g.:

    auto get(char* x) { return [x]{ std::cout << x << "\n";  }; }
    
  2. Return a type-erased representation of the lambda function:

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

Which one to choose depends on your needs. The second one is conceptually closer to the function pointer. The first one is more efficient but requires the function to be inline (or, at least, visible where used).



标签: c++ lambda