AturSams
AturSams

Reputation: 7952

Is there any way to go back from `std::function` to a pointer?

Imagine the following scenario:

typedef std::function<float(float)> A;
typedef float(*B)(float);

A foo();
void bar(B b);

You wish to do something along the lines of:

bar(foo());

Obviously this does not work. Mainly because A can contain a state and B is a function pointer. What if we know that A does not contain a state and we wish to somehow take it's "meaning" and put it into something that can be passed for a B?

Is it impossible?

Upvotes: 3

Views: 184

Answers (3)

Barry
Barry

Reputation: 302757

What if we know that A does not contain a state and we wish to somehow take it's "meaning" and put it into something that can be passed for a B?

Even that isn't sufficient. std::function provides a target() member function, that if you know the exact type of the underlying functor, you can get it back. So we can do, for instance:

void print(int i) { std::cout << i; }

std::function<void(int)> f = print;
auto ptr = f.target<void(*)(int)>();  // not null
(*ptr)(42);                           // works

However, even if our functor f doesn't contain state, that doesn't mean that its underlying type is precisely void(*)(int). It could be a completely different function pointer, in which case we wouldn't be able to pull it out:

int square(int i) { return i*i; }

f = square;
ptr = f.target<void(*)(int)>(); // nullptr!

Or it could be a lambda, in which case we wouldn't even be able to name the type, much less pull it out:

f = [](int i){ std::cout << i; }; // same as print, right?
ptr = f.target<void(*)(int)>();   // ... nope :'(

Basically, type erasure is really type erasure. If you need the original underlying type, that's likely indicative of a bad design.

Upvotes: 0

iDingDong
iDingDong

Reputation: 456

If you can ensure that the callable object stored in A is a function pointer or a lambda with an empty capture list, you can simply get a function pointer in this way:

foo().target<B>();

Upvotes: 4

In general, a std::function can "box" some closure (e.g. the value of some lambda function). And a closure contains both code and data (the closed values). So I believe that you cannot portably convert it to a naked function pointer. BTW, because conceptually closures are mixing code and data languages not providing them (like C) practically requires callbacks (i.e. the convention to pass every function pointer with some additional data, look into GTK for a concrete example).

Some implementation specific tricks might make a trampoline function on the stack (e.g. dynamically generate, perhaps with asmjit, some machine code containing a pointer to the closure, etc.). But this is not portable and system specific (in particular because the stack needs to be executable)

Upvotes: 2

Related Questions