On Monday, 24 April 2017 at 04:21:36 UTC, Manu wrote:

struct X {}

struct Y {
  this(auto ref X x)
  {
    static if (__traits(isRef, x))
    {
      // x is lvalue, copy construct
    }
    else
    {
      // x MUST be rvalue(?), move construct
// does this pattern require that I invalidate x the same way C++ does such that X's destructor won't clean up or crash?

"Require" is a bit too strict. But yes, if the pattern is to assume ownership of x's contents, then you should clear it.

Is this solid? I have a vague memory of thinking on this once and realising there was some edge case where it was logically flawed, but I can't remember clearly.

Assuming this does work, the next issue is something that mirrors std::move(), is there already such a thing?

We can't truly override move semantics in D. The language went "all in" and left little leeway to us users in that regard. Interestingly enough, we *can* come close in cases such as the code below.

struct X {}

struct Y {
  this(ref const X x)
  {
    // x is lvalue reference, copy construct
  }
  this(X x)
  {
// x is an lvalue... which may be a copy of another lvalue. can't move
construct :/

Why not? The first overload will be called with an lvalue, i.e:

X x;
Y y1 = x;

The second one will be called in all other cases:

Y y2 = X();
Y y3 = move(x); // move(x) returns X

For second overload, x will be destructed once the ctor returns. I don't see any reason why you wouldn't move it's guts out.

I guess the question in this case is how overload selection may or may not work... I didn't test this, but I expect it's an ambiguous call given an lvalue?

There is no ambiguity there as far as I can tell.
Same goes for opAssign, you can have

ref opAssign(ref X x) { /*...*/ } // assign lvalue
ref opAssign(X x) { /*...*/ } assign rvalue

I guess you mean that you don't have source for X. But in that case, you won't be able to "move-construct" Y from X in C++ either. Nor would the compiler. If you at least know the exact memory layout of X, you could hack together a custom move:

this(X x)
{
    auto px = cast(XLayout*)cast(void*)&x;
    // move from px...
}

...but that's neither here nor there. The words "dangerous", "non-portable" and UB march with pitchforks right behind that pattern ;)

Reply via email to