Move Constructor Syntax
Timon Gehr
timon.gehr at gmx.ch
Wed Oct 16 00:22:41 UTC 2024
On 10/15/24 18:57, Manu wrote:
> On Tue, 15 Oct 2024, 23:06 RazvanN via Digitalmars-d, <digitalmars-
> d at puremagic.com <mailto:digitalmars-d at puremagic.com>> wrote:
>
> On Tuesday, 15 October 2024 at 12:56:35 UTC, RazvanN wrote:
>
> >> Isn't this the exact moment that the recursion ends? If the
> >> copy ctor was an exact match (we must have been supplied an
> >> lvalue), and (therefore) while considering the move
> >> constructor it was determined that a copy is necessary, then
> >> it is not an exact match... copy ctor wins. Case closed.
> >>
>
> Note that today, from the compilers perspective both the move
> ctor and
> the copy ctor are exact matches. However, the compiler does a
> thing called
> partial ordering where it selects the function that is more
> specialized.
> This is where ref gets picked of rvalue because it is deemed more
> specialized.
>
> So, all you need to do is just tweak this and simply add a check
> for the situation
> where a copy constructor is preferred over the move constructor.
>
>
> Okay, but again with the constructor; does that rule generalise to any
> regular function argument?
>
The recursion issue is more of an implementation detail.
How does the compiler determine which of `foo(S)` and `foo(ref S)` is
more specialized? Well, I'd expect it tries to call each with the other
kind of argument.
Then, `foo(ref S)` cannot be called with (rvalue) `S`.
We still have to check the converse, as if that does not work, the
overloads are ambiguous and the compiler has to error out: `foo(S)` can
be called with `ref S`, but requires copy construction. So here, the
compiler will check whether `ref S` is copyable.
So by default, if you have `this(ref S)` and this(S)` as matches, to
pick which one to choose, it will again try to call `this(S)` with a
`ref S`. To check whether this call works, it has to be determined
whether `S` is copyable, so it will try to find a copy constructor
again, etc. Stack overflow.
So the situation is:
Overload resolution on { this(ref S), this(S) } recurses on itself.
Overload resolution on { foo(ref S), foo(S) } recurses on { this(ref S),
this(S) }, which then recurses on itself.
I think it is hard to answer a question whether the "rule generalizes".
Explicit base cases are needed that avoid stack overflow, at least for
constructors. Other functions will then indeed work the same way,
whether they are special-cased in the implementation as base cases or not.
I think this is not an insurmountable problem, just annoying to fix.
More information about the Digitalmars-d
mailing list