www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - c++ interop in the library (just for fun)

reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
May 29 2013
parent reply Martin Nowak <code dawg.eu> writes:
On 05/30/2013 03:05 AM, Adam D. Ruppe wrote:
 Maybe if we were to see this through it could be a good enough hack for
 some real world use too.

That's really need. It could also allow you to access namespaces and operators.
May 30 2013
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
We need to support different C++ name mangling schemes. Maybe a template
argument that would indicate which scheme to choose from.

Also the next step would be:
mixin(importCPP("myheader.h"));

string importCPP(string file){
auto text = import(file);
return process_text(text);
}

doesn't have to work in 100% cases, but that would be an awesome feature.

On Thu, May 30, 2013 at 7:12 AM, Martin Nowak <code dawg.eu> wrote:

 On 05/30/2013 03:05 AM, Adam D. Ruppe wrote:

 Maybe if we were to see this through it could be a good enough hack for
 some real world use too.

That's really need. It could also allow you to access namespaces and operators.

May 30 2013
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 30 May 2013 at 17:29:42 UTC, Timothee Cour wrote:
 We need to support different C++ name mangling schemes.

Right, that's fairly straightforward to implement, we could probably use a UDA to change it ( VisualCpp void foo()) or choose the most sane default with version(Windows), version(GDC), etc.
 Also the next step would be:
 mixin(importCPP("myheader.h"));

You know I was actually thinking about that. Either using a dummy D class and going over it to build the C++ object: class Test_Cpp { int num; int num2; void talk(); final void sayHi(); // or whatever i dont have the file open right now } alias AccessCpp!Test_Cpp Test; // AccessCPP parses it into the equivalent c++ definitions then builds out the structs and mangle schemes Or reading the .h file like you said. Which would be pretty hard, even to do just partially, since the C++ definition might have inline definitions, #includes, macros and so on that just totally confuse the parser.
May 30 2013