11

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>();

}
Community
  • 1
  • 1
danijar
  • 32,406
  • 45
  • 166
  • 297
  • 2
    Not using universal capture clause might be a good start. – Bartek Banachewicz Apr 01 '13 at 18:13
  • i can't think a decent api doesn't have a way for you to pass some argument pointer that will be supplied to your callback. so most likely you do *not* need the lambda as a raw function pointer – Cheers and hth. - Alf Apr 01 '13 at 18:13
  • @Cheersandhth.-Alf. The API of Google's V8 expects me to pass the function I want to bind as `InvocationCallback` which actually is a function pointer with the signature `Handle(Arguments const &)`. I wrote that in my question. – danijar Apr 01 '13 at 18:18
  • @danijar: there's no way to do directly what you ask, but this is an XY-question: asking for help with the problems of an imagined solution Y to a problem X. My comment was about your real problem X. Your response to that was about your imagened solution Y. You need to describe the real problem X. In order for people to be able to help you in a more concrete, detailed way. – Cheers and hth. - Alf Apr 01 '13 at 18:23
  • @Cheersandhth.-Alf. Sorry, I didn't get that. What exactly should I elaborate on? The issue is to only pass a lambda as `std::function` but get a raw function pointer from that. – danijar Apr 01 '13 at 18:27
  • See also: http://stackoverflow.com/questions/23795348/how-to-assign-functor-to-function-pointer – rwong Jul 14 '15 at 03:20

2 Answers2

6

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).

newacct
  • 119,665
  • 29
  • 163
  • 224
  • Thanks, I will do some research. Can't I somehow caste the closure to a `std::function(Classname* this, Arguments const &)>` and `std::bind` first parameter which would be the reference to the captured instance? The API allows me to pass an additional value which could be the reference pointer. But how can I define my `Bind()` function to only expect string name and closure, then? – danijar Apr 01 '13 at 23:46
  • @danijar: whatever you do, you will still be left with a function object, not a plain function. – newacct Apr 02 '13 at 01:27
  • That's too bad. I would have preferred a solution where only a closure is passed to the `Bind` function and it function pointer and state are split then. Since that's not possible, what is the minimal interface for my `Bind` function then? – danijar Apr 02 '13 at 09:00
0

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

Community
  • 1
  • 1
user1095108
  • 14,119
  • 9
  • 58
  • 116