Convert lambda with capture clause stored in std::

2019-02-22 03:38发布

问题:

Since my last recent question was unfortunately worded and resulted in a solution to another problem then mine, here I will try to formulate my actual problem in a clear way.

Before we start, as a sidenote, I am integrating the Javascript Engine V8 into my C++ application. That's where all the types in the example come from. And that's also the reason for the fact that I need a raw function pointer in the end. But I elaborate on this below.

From inside a class I need to pass a lambda expression with the capture clause [=] as parameter of the type std::function to another function and cast it to a raw function pointer there.

In this code, InvocationCallback is simply a typedef for a function with the signature Handle<Value>(Arguments const &).

typedef Handle<Value> (*InvocationCallback)(Arguments const &);

void Bind(string Name, function<Handle<Value>(Arguments const &)> Function)
{
    InvocationCallback* function = Function.target<InvocationCallback>();
}

All the lambda expressions have the same signature, too. Note that Handle<String> is compatible to Handle<Value> in this example. It's given by the Javascript Engine V8, too.

Bind("name", [=](const Arguments& args) -> Handle<Value>{
    Handle<String> result = String::New(Name().c_str());
    return result;
});

C++ allows me to pass this lambda as std::function to the function above. But I guess a lambda expression also stores a reference to object it refers. Somehow the access specified by [=] must be realized. That might be the reasons that casting the std::function to a raw function pointer fails.

InvocationCallback* function = Function.target<InvocationCallback>();

There is neither a compile time error nor a runtime error but the debugger tells me that it results in a null pointer. But I need the raw function pointer for further processing. I guess I could convert the lambda after std::binding the reference or this-pointer first.

Update: Since it seems to be impossible to get the state out of the lambda, this is what I tried. It compiles but function come out to be a null pointer.

Bind("name", this, [](Base* object, const Arguments& args) -> Handle<Value>{
    return v8::String::New(((Derived*)object)->Name().c_str());
});

void Bind(string Name, Module *Object, function<Handle<Value>(Module*, Arguments const &)> Function)
{
    function<Handle<Value>(Arguments const &)> method = std::bind(Function, Object, std::placeholders::_1);
    InvocationCallback* function = method.target<InvocationCallback>();

}

回答1:

You can't, because a lambda which captures is a closure, so it has state (it is an object with instance variables). A function pointer has no state. Thus, you cannot do this without either 1) the API you are using that requires the function pointer also allows you to pass a user data argument where you pass the state, or 2) storing the state in a global variable or something.

Search around Stack Overflow for "member function to callback" and you will get an idea (basically, you are wanting to use a member function, the operator(), as a callback).



回答2:

You can convert a capturing lambda/functor into a function pointer, but you need to be careful when doing it:

https://codereview.stackexchange.com/questions/79612/c-ifying-a-capturing-lambda