3 ms·
> E.g. every C++ library should come with an optional C-API to simplify language bindings, or even just compiling that library into a DLL. hard to do without
by jcelerier 6y ago
> E.g. every C++ library should come with an optional C-API to simplify language bindings, or even just compiling that library into a DLL.
hard to do without incurring additional dynamic allocations though. e.g. how would you make, say, an API that wraps construction / doing stuff / destruction of something that'd look like this :
namespace mylib {
struct node {
std::vector<node> children;
std::optional<float> value;
};
}
in C you'd likely have to have something that looks like
mylib_node* mylib_node_alloc(void);
void mylib_node_free(mylib_node*);
// and then...
float* mylib_node_value(mylib_node*); // this ?
float mylib_node_value(mylib_node*, int* ok); // or this ?
void mylib_node_set_value(mylib_node*, float value, int set); // then there's this ?
void mylib_node_set_value(mylib_node*, float* value); // or this ?
void mylib_node_unset_value(mylib_node*); // or maybe this ?
and all this cannot really be done without a dynamic allocation (which hopefully looks terrible to everyone), unless you fancy doing ugly ugly ugly stuff like
struct mylib_node { char storage[sizeof c++ struct that was computed manually)]; };
so anything that'd allow other languages to understand at least C++ vocabulary would be a great boon in terms of perf, etc
- maccard 6y agoYou can do something like // Or replace with something like a Strong Type; https://www.fluentcpp.com/2017/05/05/news-strong-types-are-free/ using NodeHandle = int; struct OptFloat { float Value; bool bInitialized = false; }; NodeHandle CreateNode(NodeHandle* Children, int NumChildren, OptFloat Value); void DestroyNode(NodeHandle ToDestroy); void SetValue(NodeHandle ToSet, OptFloat NewValue); Aside from that, you do raise a good point. If you implemented your C api over your implementation of node, you would be in for a bad time as the owning std::vector<node> won't keep valid your pointers valid.. This isn't suposed to be ragging on your code, it's really to point out the pitfalls of manual APIs. > struct mylib_node { char storage[sizeof c++ struct that was computed manually)]; }; You can do; // IN C api, fill this in manually #define mylib_storagsize = ? struct mylib_node {char storage[MYLIB_STORAGESIZE]; }; // or; struct mylib_node {void* storage; } // in node.cpp - the underlying C++ abstraction; static_assert(sizeof(mylib::node) == MYLIB_STORAGESIZE); It's only _slightly_ better..