I have some C++ code that returns a std::function
. I would like to call this from some C code. Is this possible? As an example I have the following code:
typedef std::function<int(int)> AdderFunction; AdderFunction makeAdder(int amount) { return [amount] (int n) { return n + amount; }; } extern "C" { AdderFunction makeCAdder(int amount) { return makeAdder(amount); } }
with clang++ -std=c++11 test.cpp
it results in the following warning:
'makeCAdder' has C-linkage specified, but returns user-defined type 'AdderFunction' (aka 'function<int (int)>') which is incompatible with C
I understand why this is happening, but wondering if there is a pattern to make it possible?
std is the namespace and by using :: (after the std) you explicitly using the functions of the namespace std. Now, imagine that you create your own namespace and some of the functions that you have created there have the same name as the functions in std namespace.
The stored callable object is called the target of std::function . If a std::function contains no target, it is called empty. Invoking the target of an empty std::function results in std::bad_function_call exception being thrown.
You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.
If there is any possibility you are storing a copy of the std::function , pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function and having one sub method after another use it. Barring that, a move will be as efficient as a const& .
The most portable method to interface between C/C++ will be to use pointers to pass data between languages and use non-member functions to make function calls.
The .h file:
#ifdef __cplusplus extern "C" { #endif // Declare the struct. struct Adder; // Declare functions to work with the struct. Adder* makeAdder(int amount); int invokeAdder(Adder* adder, int n); void deleteAdder(Adder* adder); #ifdef __cplusplus } #endif
Implement them in a .cpp file as:
#include <functional> typedef std::function<int(int)> AdderFunction; struct Adder { AdderFunction f; }; AdderFunction makeAdderFunction(int amount) { return [amount] (int n) { return n + amount; }; } Adder* makeAdder(int amount) { Adder* adder = new Adder; adder->f = makeAdderFunction(amount); return adder; } int invokeAdder(Adder* adder, int n) { return adder->f(n); } void deleteAdder(Adder* adder) { delete adder; }
It's not possible to call a std::function
from C, because C doesn't support the language features that are required. C doesn't have templates, access modifiers, callable objects, virtual methods, or anything else that std::function
could use under the hood. You need to come up with a strategy that C can understand.
One such strategy is to copy/move your std::function
to the heap and return it as an opaque pointer. Then, you would provide another function through your C++ interface that takes that opaque pointer and calls the function that it contains.
// C side struct function_opaque; int call_opaque(struct function_opaque*, int param); // C++ side extern "C" { struct function_opaque { std::function<int(int)> f; }; int call_opaque(function_opaque* func, int param) { return func->f(param); } };
Of course, this comes with memory management implications.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With