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 <[email protected]> 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 <[email protected]> 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.

Reply via email to