First, while it looks Swift will have a great support for C++ in the near future, for now you will need to create simple C wrappers to your interfaces.
I will tell you what i do here:
I register a callback in swift that is a c callback, but always pass a 'state' option to the C function.
like this:
I define a callback structure in C like
(thing.h) C++: suppose you have this class
class Thing {
public:
bool A(int x, int y);
bool B(int x, int y, int z);
bool C(int x);
};
thing_shims.h:
typedef void* CThing;
typedef struct {
int(*callA)(void* state, int x, int y);
int(*callB)(void* state, int x, int y, int z);
} ThingCallbacks;
CThing _CThingCreate(void*, ThingCallbacks callbacks);
void _CThingDestroy(CThing);
int _CThingC(CThing, int x);
in Swift:
import CThingShims // this is the native shim C library
// NOTE: you will need to use a class not a struct, giving you will use its raw pointer
// as the state that C will pass it over back to you
Class Thing {
// this is the wrapper created on C++ size.. unfortunatelly it needs to be heap allocated
// we can manage its lifetime bounded with the lifetime of this class by using deinit {}
// to destroy the heap allocated wrapper
let reference: CThing
init() {
var callbacks = ThingCallbacks()
// zero out the struct
memset(&callbacks, 0, MemoryLayout<ThingCallbacks>.stride)
// now here is the trick
callbacks.callA = {
(handle: UnsafeMutableRawPointer?,
x: CInt,
y: CInt) -> CInt in
let this = unsafeBitCast(handle, to: Thing.self)
return this.A(x: Int(x), y: Int(y)) ? 1 : 0
}
callbacks.callB = {
(handle: UnsafeMutableRawPointer?,
x: CInt,
y: CInt,
z: CInt,) -> CInt in
let this = unsafeBitCast(handle, to: Thing.self)
return this.B(x: Int(x), y: Int(y), z: Int(z)) ? 1 : 0
}
let this = unsafeBitCast(Unmanaged.passUnretained(self).takeUnretainedValue(), to: UnsafeMutableRawPointer.self)
reference = _CThingCreate(this, callbacks)
}
deinit {
_CThingDestroy(reference)
}
func A(x: Int, y: Int) -> Bool {
// do your swift thing here
return doA()
}
func B(x: Int, y: Int, z: Int) -> Bool {
// do your swift thing here
return doB()
}
func C(x: Int) -> Bool {
return _CThingC(reference, CInt(x)) != 0
}
}
now on C++ (thing.cc or thing.cpp file):
class ThingWrapper : public mycode::InterfaceCppWillCall {
public:
ThingWrapper(Thing* real_thing, void* state, ThingCallbacks callbacks):
real_thing_(real_thing),
state_(state),
callbacks_(callbacks) {
real_thing_->register(this);
}
// here your C++ code will call (A and B on Swift)
bool A(int x, int y) override {
return callbacks_.callA(state, x, y) != 0;
}
bool B() override {
return callbacks_.callB(state, x, y, z) != 0;
}
// here the Swift code will call C++
bool C() {
return real_thing_->C();
}
private:
Thing* real_thing_;
void* state_;
ThingCallbacks callbacks_;
};
CThing _CThingCreate(void* state, ThingCallbacks callbacks) {
// Get Thing here somehow
Thing* real_thing = ...
return new ThingWrapper(real_thing, state, callbacks);
}
void _CThingDestroy(CThing handle) {
reinterpret_cast<ThingWrapper *>(handle);
}
int _CThingC(CThing, int x) {
return reinterpret_cast<ThingWrapper *>(handle)->C() ? 1 : 0;
}
Note that on your C++ code you create the mycode::InterfaceCppWillCall {} interface so your C++ code needs to only use that as a reference.
class InterfaceCppWillCall {
public:
virtual bool A(int x, int y) = 0;
...
};
class Thing {
public:
// a method or in the constructor if you can
void register(InterfaceCppWillCall* interface) {
interface_ = interface;
}
bool A(int x, int y) { return interface_->A(x, y); }
...
private:
InterfaceCppWillCall* interface_;
};
Its a little work, but its doable.
I hope it helps.