On Sunday, 6 October 2024 at 16:43:34 UTC, Paul Backus wrote:
>On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
>As the above illustrates, a move constructor cannot be distinguished from a regular constructor by syntax alone. It needs semantic analysis.
It's worth pointing out that this is not just a problem for move constructors; it's also a problem for copy constructors. Specifically, it's what prevents copy constructors from being templates.
As a result, if you're writing generic code and want to handle arbitrary combinations of type qualifiers on the original object and the copy, you cannot do the simple, obvious thing and use a template, like this:
this(this This, Other)(ref Other other)
if (is(immutable Other == immutable typeof(this))
{
// copy logic
}
Instead, you must write individual copy constructor overloads for every combination of qualifiers:
// Function bodies omitted for brevity
// mutable original
this(ref typeof(this));
this(ref typeof(this)) const;
this(ref typeof(this)) immutable;
this(ref typeof(this)) inout;
// const original
this(ref const typeof(this));
this(ref const typeof(this)) const;
this(ref const typeof(this)) immutable;
this(ref const typeof(this)) inout;
// immutable original
this(ref immutable typeof(this));
this(ref immutable typeof(this)) const;
this(ref immutable typeof(this)) immutable;
this(ref immutable typeof(this)) inout;
// inout original
this(ref inout typeof(this));
this(ref inout typeof(this)) const;
this(ref inout typeof(this)) immutable;
this(ref inout typeof(this)) inout;
// etc.
So, whatever solution we come up with for helping the compiler identify move constructors, I hope we can apply it to copy constructors too.
I have similar problem in implementation of generic container:
static if(isCopyConstructable!(typeof(this), typeof(this)))
this(ref scope typeof(this) rhs)@safe{this(rhs, Forward.init);}
else
@disable this(ref scope typeof(this) rhs)@safe;
static if(isCopyConstructable!(typeof(this), const typeof(this)))
this(ref scope typeof(this) rhs)const @safe{this(rhs, Forward.init);}
else
@disable this(ref scope typeof(this) rhs)const @safe;
static if(isCopyConstructable!(typeof(this), immutable typeof(this)))
this(ref scope typeof(this) rhs)immutable @safe{this(rhs, Forward.init);}
else
@disable this(ref scope typeof(this) rhs)immutable @safe;
static if(isCopyConstructable!(typeof(this), shared typeof(this)))
this(ref scope typeof(this) rhs)shared @safe{this(rhs, Forward.init);}
else
@disable this(ref scope typeof(this) rhs)shared @safe;
static if(isCopyConstructable!(typeof(this), const shared typeof(this)))
this(ref scope typeof(this) rhs)const shared @safe{this(rhs, Forward.init);}
else
@disable this(ref scope typeof(this) rhs)const shared @safe;
Having template copy/move ctor will be nice.