Who says we can't call C++ constructors?

Atila Neves atila.neves at gmail.com
Tue Apr 24 11:19:59 UTC 2018


On Monday, 23 April 2018 at 20:40:47 UTC, Manu wrote:
> On 23 April 2018 at 07:27, Atila Neves via 
> Digitalmars-d-announce <digitalmars-d-announce at puremagic.com> 
> wrote:
>> On Saturday, 21 April 2018 at 18:11:09 UTC, Manu wrote:
>>>
>>> On 21 April 2018 at 05:41, Atila Neves via 
>>> Digitalmars-d-announce <digitalmars-d-announce at puremagic.com> 
>>> wrote:
>>>>
>>>> [...]
>>>
>>>
>>> Paste the pre-processed D code?
>>> Did you generate the C++ mangled symbol name and call it from 
>>> a D
>>> wrapper? I've attempted that before in 'normal' D ;)
>>
>>
>> Mostly just constructors with `pragma(mangle)` but having move 
>> work correctly involved two wrappers, one taking by value and 
>> one taking by non-const ref.
>
> Can you explain the move issue? That's interesting.

Sure.

I thought about generating D wrappers for everything, but in TDD 
fashion I tried slapping a pragma(mangle) on the copy constructor 
and things just worked. Odd then that dmd doesn't try to 
correctly mangle constructors and destructors since they're 
perfectly callable.

But then there's the move constructor. There's no signature I can 
use for it exactly, so how do I hack that? Well, in D a move 
would be done by value, but that doesn't quite work, since:

this(ref const(T));
this(T);

And:

auto t1 = T(42);
auto t2 = T(t1);

Causes t2 to be constructed with the by value version instead of 
the copy constructor. Clearly not what we want. So I do this:

this(ref const(T));
this(ref T other) {
    this(*cast(const T*)(&other));
}
this(T);

And now rvalues go to the by-value version, and lvalues to the 
copy constructor. What to do with the by-value constructor?

pragma(mangle, "<whatever>") this(T* );  // C++ move constructor
this(T other) {
     this(&other);
     other = T.init; // to avoid problems
}

And now rvalues go to the C++ move constructor. Since the D 
definition is in the same module it will probably be inlined as 
well.

The only thing left is to enable explicit moving of lvalues. The 
thing is that I'm already injecting code into the user's file 
anyway, so maybe I can use that to enable moves? I can't put the 
code into a different module (or maybe I can, I might do that 
later), so to namespace it I put it in a struct called dpp:

struct dpp {
     static struct Move(T) {
         T* ptr;
     }

     static auto move(T)(ref T value) { // by ref so only lvalues 
apply
         return Move!T(&value);
     }
}

And we emit another constructor with code in it for the user:

this(Move!T wrapper) {
     this(wrapper.ptr);  // calls the C++ move constructor
}

And Bob's your uncle.


More information about the Digitalmars-d-announce mailing list