c++ interop in the library (just for fun)
Adam D. Ruppe
destructionator at gmail.com
Wed May 29 18:05:28 PDT 2013
So now that there's a pragma(mangle), we can start hacking this
up! I'm using Linux g++ 32 bit.
C++:
class Class {
public:
Class() {}// printf("constructed\n"); }
virtual void addNum(int a) { num += a; }
virtual void addNum2(int a) { num2 += a; }
void talk() { printf("%d %d\n", num, num2); }
int num;
int num2;
};
D:
struct Class {
extern(C++) interface Vtable {
void addNum(int num);
void addNum2(int num2);
}
mixin CPlusPlusObject!(Vtable, typeof(this));
void cppCtor();
extern(C++) void talk();
int num;
int num2;
}
magic D:
string cppMangleCtor(alias Func)() {
import std.conv;
string m = "_ZN";
string cn = __traits(parent, Func).stringof;
m ~= to!string(cn.length) ~ cn;
m ~= "C2Ev"; // fixme: the actual argument list
return m;
}
string CppCtors(T)() {
string code;
foreach(member; __traits(allMembers, T)) {
static if(member == "cppCtor") {
code ~= "pragma(mangle,
`"~cppMangleCtor!(__traits(getMember, T, member))~"`) static
extern(C++) void cppConstructor("~T. stringof~"*);";
code ~= "\n";
code ~= "static " ~ T.stringof ~
" opCall() {
auto c =
"~T.stringof~".init;
cppConstructor(&c);
return c;
}";
}
}
return code;
}
mixin template CPlusPlusObject(Virtuals, Main) {
void* virts;
Virtuals getVirtuals() { return cast(Virtuals)
&this; }
alias getVirtuals this;
@disable this();
mixin(CppCtors!Main());
pragma(msg, CppCtors!Main());
}
Test functions, D:
extern(C++) void doit(Class*);
extern(C++) void whoa(Class* c) {
import core.stdc.stdio;
printf("whoa\n");
c.num += (30);
c.talk();
c.addNum(10);
}
void main() {
import std.stdio;
writeln("MOVING ON");
auto c = Class.opCall();
doit(&c);
writeln("All Done!");
}
C++:
extern void whoa(Class* c);
void doit(Class* ptr) {
if(ptr == NULL)
ptr = new Class2();
ptr->num = 10;
ptr->num2 = 20;
ptr->talk();
whoa(ptr);
ptr->talk();
}
Output:
$ ./testcpp
MOVING ON
constructed
10 20
whoa
40 20
50 20
All Done!
No crash! Now, normally, I'd say we should probably construct the
objects in their native language, but I just had to try this and
the fact that it worked I thought was pretty cool.
Here we see access to both virtual and non-virtual member
functions of the C++ object from D, as well as direct access to
the member variables! Liable to break? Oh yeah. Hacky?
Definitely. But I thought this was kinda cool.
Inheritance can work too, but there's still a ways to go to make
that right. (It works easily enough if you just access virtuals
though, D's plain extern(C++) interface can do that.)
Maybe if we were to see this through it could be a good enough
hack for some real world use too.
More information about the Digitalmars-d
mailing list