I’m working on a C++ library and was wondering about compatibility within it’s own API and ABI. I stumbled upon this (Creating Library with backward compatible ABI that uses Boost) which gave some helpful tips.
The problem I’m facing is trying to create a C interface that doesn’t use STL/Boost and somehow get the same functionality as the backend which does use them. Some of my interface functions require allowing the user to bind function pointers. Normally I’d use boost bind/function for this but now I can’t.
An example to illustrate the problem:
PRIVATE/INTERNAL:
class TestClass
{
public:
typedef boost::function<void (void)> FuncType;
public:
TestClass( FuncType f ) : m_Func(f)
{
}
void operator()()
{
m_Func();
}
private:
boost::function<void (void)> m_Func;
};
void* createTestClass(...)
{
TestClass* fooHandle = new TestClass(boost::bind(...));
return fooHandle;
}
PUBLIC INTERFACE:
extern "C" void* createTestClass(...);
CLIENT’S CODE:
void doSomething()
{
}
class DoStuffClass
{
public:
void Stuff() {}
};
createTestClass(&doSomething);
DoStuffClass stuff;
createTestClass(&DoStuffClass::Stuff, &stuff);
I can probably make this work for simple function pointers but for member functions is there a way? What would I put in the ... sections?
Cheers!
If you’re going to try to define your own delegates to wrap C++ member functions, free functions etc., I suggest you take a look at “5 years later, is there something better than the “Fastest Possible C++ Delegates”?. The discussion is quite nice and the accepted answer proposes a neat trick to reduce all callbacks to a pair of
void*and some free functionR(void*,...)that invokes a member function or free function and whatnot.I’ve used a similar technique to implement wrappers for Win32 API callbacks. Here’s an example (take a look at the
Timer::function<>andTimer::method<>inner types). Using this technique, you can expose a C interface like:The role of the proposed mechanism is just generation of the
void(void*,int,int)functions that wrap member function calls so that they have the right signature. Everything else is just plain C function pointers and can be freely passed to your C API while preserving the ABI.Just be careful exceptions don’t leak from your C++ callback functions. See “Passing C++ exceptions across a C API boundary” for a more detailed discussion of the topic.
Update (working example)
Here’s a full working example (tested with Visual Studio 2008).
library.h (public interface for C or C++ clients with stable ABI)
library.c (library implementation)
This demonstrates a C implementation, but you could have a C++ file instead and use
std::function<>,boost::function<>or other to use the callback.library.hpp (enhanced interface for C++ clients, builds on public ABI)
This is the enhanced interface for C++ clients. It adds support for using member functions instead of plain
int(void*,int,int)free functions. If you only plan to support C++ clients, then this can be in the same file as your C-style interface.main.cpp (test program)
Here’s a simple demo on using the interface:
You should expect this program to output
Foo::bar(1, 2)since the registered callback function will invokefoo.bar(1,2).