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