Jump to page: 1 24  
Page
Thread overview
How to pass a class by (const) reference to C++
Dec 12, 2021
Jan
Dec 13, 2021
evilrat
Dec 13, 2021
Jan
Dec 13, 2021
Tejas
Dec 13, 2021
evilrat
Dec 13, 2021
evilrat
Dec 13, 2021
Jan
Dec 13, 2021
Tim
Dec 13, 2021
Jan
Dec 13, 2021
Jan
Dec 13, 2021
Tim
Dec 14, 2021
Tejas
Dec 14, 2021
evilrat
Dec 15, 2021
Jan
Dec 15, 2021
Jan
Dec 15, 2021
rikki cattermole
Dec 15, 2021
Jan
Dec 15, 2021
evilrat
Dec 15, 2021
Jan
Dec 15, 2021
Tim
Dec 15, 2021
Jan
Dec 15, 2021
Tim
Dec 15, 2021
Jan
Dec 15, 2021
H. S. Teoh
Dec 15, 2021
Adam Ruppe
Dec 15, 2021
Tim
Dec 15, 2021
Jan
Dec 15, 2021
Tim
Dec 15, 2021
Jan
Dec 16, 2021
Jan
Dec 16, 2021
Tim
Dec 16, 2021
Jan
Dec 15, 2021
Adam D Ruppe
December 12, 2021

In D I have an extern(C++) class:

extern(C++) class A
{
    ~this();

    // other stuff
}

An a function that takes A by const reference:

void CppFunc(const A& arg);

But how do I bind this in D ?

extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass as 'A const * const &'

I have solved similar problems with other classes by declaring them as struct in D, but that only works for classes that have no virtual functions. I now have a class where I do need to use a class on the D side, and now I have problems passing these objects to C++.

December 13, 2021

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

>

In D I have an extern(C++) class:

extern(C++) class A
{
    ~this();

    // other stuff
}

An a function that takes A by const reference:

void CppFunc(const A& arg);

But how do I bind this in D ?

extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass as 'A const * const &'

I have solved similar problems with other classes by declaring them as struct in D, but that only works for classes that have no virtual functions. I now have a class where I do need to use a class on the D side, and now I have problems passing these objects to C++.

You can tell compiler to mangle it as struct/class using extern(C++, struct).

extern (C++, struct) // will use struct mangling even though it's a class
class SomeDClass
{
 ...
}
December 13, 2021

On Monday, 13 December 2021 at 07:48:34 UTC, evilrat wrote:

>

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

>

In D I have an extern(C++) class:

extern(C++) class A
{
    ~this();

    // other stuff
}

An a function that takes A by const reference:

void CppFunc(const A& arg);

But how do I bind this in D ?

extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass as 'A const * const &'

I have solved similar problems with other classes by declaring them as struct in D, but that only works for classes that have no virtual functions. I now have a class where I do need to use a class on the D side, and now I have problems passing these objects to C++.

You can tell compiler to mangle it as struct/class using extern(C++, struct).

extern (C++, struct) // will use struct mangling even though it's a class
class SomeDClass
{
 ...
}

I tried this, but it doesn't work, because it seems D decides how to pass the object by whether it is a class or struct in D, not in C++. So even with the change as you suggested it, it still tries to pass the object as a pointer to begin with.

December 13, 2021

On Monday, 13 December 2021 at 09:21:26 UTC, Jan wrote:

>

On Monday, 13 December 2021 at 07:48:34 UTC, evilrat wrote:

>

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

>

In D I have an extern(C++) class:

extern(C++) class A
{
    ~this();

    // other stuff
}

An a function that takes A by const reference:

void CppFunc(const A& arg);

But how do I bind this in D ?

extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass as 'A const * const &'

I have solved similar problems with other classes by declaring them as struct in D, but that only works for classes that have no virtual functions. I now have a class where I do need to use a class on the D side, and now I have problems passing these objects to C++.

You can tell compiler to mangle it as struct/class using extern(C++, struct).

extern (C++, struct) // will use struct mangling even though it's a class
class SomeDClass
{
 ...
}

I tried this, but it doesn't work, because it seems D decides how to pass the object by whether it is a class or struct in D, not in C++. So even with the change as you suggested it, it still tries to pass the object as a pointer to begin with.

You'll have to use something called a shim, it seems.

For example:

main.d :


extern(C++) class A{}

extern(C++) void cppFunc_shim(A arg);

void main(){
	A a = new A();
	cppFunc_shim(a);
}

cppShim.cpp :


class A{};

extern void cppFunc(A const &arg);

void cppFunc_shim(A *param){
	const A forwardingVar = A(*param);
	cppFunc(forwardingVar);
}

cppFunc.cpp :


#include "iostream"
class A{};

void cppFunc(A const &arg){
	//std::cout << arg << std::endl;
	std::cout << "Called cppFunc :D" << std::endl;
}	

Then pass the following on the command line(assuming all files are in the same directory):

ldmd2 main.d cppFunc.o cppShim.o -L-lstdc++

That's what it took to make it work for me, dunno if more convenient methods exist.

Hope it helps :D

December 13, 2021

On Monday, 13 December 2021 at 11:13:12 UTC, Tejas wrote:

>

On Monday, 13 December 2021 at 09:21:26 UTC, Jan wrote:

>

On Monday, 13 December 2021 at 07:48:34 UTC, evilrat wrote:

>

On Sunday, 12 December 2021 at 21:24:39 UTC, Jan wrote:

>

In D I have an extern(C++) class:

extern(C++) class A
{
    ~this();

    // other stuff
}

An a function that takes A by const reference:

void CppFunc(const A& arg);

But how do I bind this in D ?

extern(C++) void CppFunc(A arg); // tries to pass as 'A*'
extern(C++) void CppFunc(ref const(A) arg); // tries to pass as 'A const * const &'

I have solved similar problems with other classes by declaring them as struct in D, but that only works for classes that have no virtual functions. I now have a class where I do need to use a class on the D side, and now I have problems passing these objects to C++.

You can tell compiler to mangle it as struct/class using extern(C++, struct).

extern (C++, struct) // will use struct mangling even though it's a class
class SomeDClass
{
 ...
}

I tried this, but it doesn't work, because it seems D decides how to pass the object by whether it is a class or struct in D, not in C++. So even with the change as you suggested it, it still tries to pass the object as a pointer to begin with.

You'll have to use something called a shim, it seems.

For example:

main.d :


extern(C++) class A{}

extern(C++) void cppFunc_shim(A arg);

void main(){
	A a = new A();
	cppFunc_shim(a);
}

cppShim.cpp :


class A{};

extern void cppFunc(A const &arg);

void cppFunc_shim(A *param){
	const A forwardingVar = A(*param);
	cppFunc(forwardingVar);
}

cppFunc.cpp :


#include "iostream"
class A{};

void cppFunc(A const &arg){
	//std::cout << arg << std::endl;
	std::cout << "Called cppFunc :D" << std::endl;
}	

Then pass the following on the command line(assuming all files are in the same directory):

ldmd2 main.d cppFunc.o cppShim.o -L-lstdc++

That's what it took to make it work for me, dunno if more convenient methods exist.

Hope it helps :D

Yeah but it sucks to have making C++ wrapper just for this. I think either pragma mangle to hammer it in place or helper dummy struct with class layout that mimics this shim logic is a better solution in such cases.
Literally anything but building C++ code twice for a project.

December 13, 2021

On Monday, 13 December 2021 at 12:08:30 UTC, evilrat wrote:

>

Yeah but it sucks to have making C++ wrapper just for this. I think either pragma mangle to hammer it in place or helper dummy struct with class layout that mimics this shim logic is a better solution in such cases.
Literally anything but building C++ code twice for a project.

Does something like this work?

class _A {}
struct A {}

extern(C++) void CppFunc(ref const(A) arg);

void func(_A a){
    CppFunc(*cast(A*)a);
}
December 13, 2021

On Monday, 13 December 2021 at 12:16:03 UTC, Ola Fosheim Grøstad wrote:

>

class _A {}
struct A {}

With extern(C++) on these…

December 13, 2021

On Monday, 13 December 2021 at 12:16:03 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 13 December 2021 at 12:08:30 UTC, evilrat wrote:

>

Yeah but it sucks to have making C++ wrapper just for this. I think either pragma mangle to hammer it in place or helper dummy struct with class layout that mimics this shim logic is a better solution in such cases.
Literally anything but building C++ code twice for a project.

Does something like this work?

class _A {}
struct A {}

extern(C++) void CppFunc(ref const(A) arg);

void func(_A a){
    CppFunc(*cast(A*)a);
}

Only if this struct matches class memory layout, the only potential problem is ctor on C++ side.
Also C++ class will likely be NOT zero initialized and have byte gaps due to alignment, this can mess up many things including (default) equality operators and such.

That example is still looks very conspicuous because it is very likely does nothing on the caller side in C++ as it passes a copy. Such things may indicate that the library author have no idea what he is doing, and it works on occasion.

All this will require extra care or it will explode in your face, and is quite hard to debug without such low-level knowledge of details.

December 13, 2021

On Monday, 13 December 2021 at 12:51:17 UTC, evilrat wrote:

>

That example is still looks very conspicuous because it is very likely does nothing on the caller side in C++ as it passes a copy.

Yes, I wouldn't want to use it, maybe manual mangling is better, but still painful. const A& is so common in C++ API's that it really should be supported out-of-the-box. All it takes is adding a deref-type-constructor to the D language spec, e.g. ref const(@deref(A))

December 13, 2021

On Monday, 13 December 2021 at 13:02:50 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 13 December 2021 at 12:51:17 UTC, evilrat wrote:

>

That example is still looks very conspicuous because it is very likely does nothing on the caller side in C++ as it passes a copy.

Yes, I wouldn't want to use it, maybe manual mangling is better, but still painful. const A& is so common in C++ API's that it really should be supported out-of-the-box. All it takes is adding a deref-type-constructor to the D language spec, e.g. ref const(@deref(A))

I fully agree. This pattern is so common in C++, that I am surprised D doesn't have a way to do this already. The whole idea of linking against C++ is to interop easily, with little friction and high performance. Needing to build any shims or redesign the C++ side is very much contrary to this goal.

Does anyone know whether such issues have been discussed before? I can't imagine I'm the first one to run into this.

« First   ‹ Prev
1 2 3 4