On 25 April 2017 at 08:46, Andrei Alexandrescu via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> On 04/24/2017 04:23 PM, ag0aep6g wrote: > >> On 04/24/2017 08:48 PM, Stanislav Blinov wrote: >> >>> Speaking of const violation and UB, std.algorithm.mutation.move seems to >>> violate const without remorse: >>> >> >> Yup. Even in @safe code, which is a bug. >> https://issues.dlang.org/show_bug.cgi?id=15315 >> > > Should fail in all situations, thanks for reporting. > > The original code should work like this: > > struct X {} > > struct Y { > private X _x; > this()(auto ref X x) > { > static if (__traits(isRef, x)) > { > _x = x; > } > else > { > import std.algorithm.mutation : move; > _x = move(x); > } > } > } > > Note how I made the ctor templated so it accepts auto ref. The less > sophisticated version is simply: > > struct X {} > > struct Y { > private X _x; > this(ref X x) > { > _x = x; > } > this(X x) > { > import std.algorithm.mutation : move; > _x = move(x); > } > } > Ah crap, I somehow missed the single-argument move() function. Okay, so this pattern is definitely reliable? I haven't seen it clearly documented anywhere that this is the prescribed pattern, and it's come up on stack overflow a few times, but it hasn't been answered correctly. I think this is poorly distributed knowledge. As Schveighoffer pointed out, this pattern requires *another* overload for `ref const X`? Surely if there is no `ref X` and only a `ref const X` available, it should choose that one rather than the byval one when the argument is not const (as demonstrated in the bug report?) It's demonstrated that `ref const X` might inhibit an efficient copy constructor implementation in some cases, but you can't have false-move's occurring when the lvalue is not const.