On Thursday, 25 July 2019 at 20:38:59 UTC, aliak wrote:
On Thursday, 25 July 2019 at 19:35:36 UTC, aliak wrote:
Basically, can template W be made to handle an S that can't be copied?

import std;

static struct S {
    int i;
    @disable this(this);
    this(int i) { this.i = i; }
}

[...]

So this works - are there any problems with it?

struct W(T) {
    T value;
    this(T value) {
        static if (isMutable!T)
            this.value = value.move;
        else
            this.value = value;
    }
}

auto wrap(T)(T value) {
    static if (isMutable!T)
        return W!T(value.move);
    else
        return W!T(value);
}

Shouldn't this be happening by default? When would you not want that to happen?

The way I handle this is with `auto ref` and `core.lifetime.forward`:

import core.lifetime: forward;

struct W(T)
{
    T value;
    this()(auto ref T value)
    {
        this.value = forward!value;
    }
}

auto wrap(T)(auto ref T value)
{
    return W!T(forward!value);
}

@safe unittest
{
    static struct NoCopy { @disable this(this); }
    assert(__traits(compiles, {
        auto test = wrap(NoCopy());
    }));
    assert(!__traits(compiles, {
        auto lval = NoCopy(); auto test = lval;
    }));
}

Interactive: https://run.dlang.io/is/kDJyYC

It's not very well documented, but `forward` does essentially the same thing as your `static if` + `move` combination.

Note that with both your version and mine, you will run into the same problem I did of `move` making it impossible to use instances of `W` in static initializers and CTFE. [1] The best compromise I was able to come up with was to only call move if `isCopyable!T == false`, which doesn't really solve the problem, but at least contains it.

[1] https://github.com/pbackus/sumtype/issues/22

Reply via email to