I'm dealing with a C system that offers a hook of this form:
int (*EXTENSIONFUNCTION)(NATIVEVALUE args[]);
It's possible to register an EXTENSIONFUNCTION and the number of arguments it takes.
My idea was that I'd make a class Extension
to wrap up an extension. It would be able to be constructed from a std::function (or any Callable, ideally, but let's just say it contains a std::function for now). And the extension takes Value parameters, which wrap up NATIVEVALUE (but are larger). I'd automatically take care of the parameter count with sizeof...(Ts)
, for instance. It might look like this:
Extension<lib::Integer, lib::String> foo =
[](lib::Integer i, lib::String s) -> int {
std::cout << i;
std::cout << s;
return 0;
}
Problem is that in order for the C library to register and call it, it wants that array-based interface. :-/
I set out to try and get the compiler to write a little shim, but I don't see a way to do it. I can have a variadic operator()
on Extension, and do a runtime loop over the NATIVEVALUE to get an array of Value[]. But what do I do with that? I can't call the std::function with it.
So it seems I need to make an EXTENSIONFUNCTION instance which calls my std::function, as a member of each Extension instance.
But basically I find myself up against a wall where I have a variadic templated class for the extension... and then a sort of "can't get there from here" in terms of taking this NATIVEVALUE args[]
and being able to call the std::function with them. If std::function would be willing to be invoked with a std::array of arguments, that would solve it, but of course that isn't how it works.
Is it possible to build a shim of this type? The "ugly" thing I can do is just proxy to another array, like:
Extension<2> foo =
[](lib::Value args[]) -> int {
lib::Integer i (args[0]);
lib::String s (args[1]);
std::cout << i;
std::cout << s;
return 0;
}
But that's not as ergonomic. It seems impossible, without knowing the calling convention and doing some kind of inline assembly stuff to process the parameters and CALL the function (and even that would work for functions only, not Callables in general). But people here have proven the impossible possible before, usually by way of "that's not what you want, what you actually want is..."
UPDATE: I just found this, which seems promising...I'm still trying to digest its relevance:
"unpacking" a tuple to call a matching function pointer
( Note: There are a few cross-cutting issues in what I aim to do. Another point is type inference from lambdas. Answer here seems to be the best bet on that... it appears to work, but I don't know if it's "kosher": Initialize class containing a std::function with a lambda )