On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote:
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote:
[...]
The problem is that the compiler will try to generate an inout
copy constructor for Bar that looks roughly like this:
```
this(ref scope inout(Bar) p) inout
{
this.foo = p;
}
```
The idea behind this lowering is to try and call the copy
constructor for Foo object if possible. One issue here is that
copy constructors have the same symbol name as constructors
(__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`.
Since both the instance and the parameter are inout, the copy
constructor of Foo cannot be called, so the templated
constructor is called. After generating the template instance
of the constructor, you end up with `this(scope inout(Foo))
inout` ; that is basically an rvalue constructor. This is not
valid code; if you write:
```
struct Foo(T){
//this(Rhs, this This)(scope Rhs rhs){}
this(scope inout(Foo!int) rhs) inout {}
this(ref scope typeof(this) rhs){
}
}
```
You will get an error stating that you cannot define both an
rvalue constructor and a copy constructor. However, since the
constructor is templated it is impossible for the compiler to
issue this error before actually instantiating the constructor.
I see 2 possible fixes for this: (1) either we rename the copy
constructor symbol to __cpCtor so that it does not clash with
the normal constructor overload set or (2) when a templated
constructor is instantiated, we can check whether it is an
rvalue constructor and issue an error if a copy constructor
exists.
When I implemented the copy constructor I thought that it would
better to have the copy constructor on a different overload set
than the normal constructors, however, Walter insisted that
they have the same name. So, I guess (2) is the way to go.
Cheers,
RazvanN
Then why did my modification work?
```d
struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}
this(scope Foo!(T)* rhs){ //replaced typeof(this) with Foo!T
and ref with pointer. Code still works if I retain typeof(this)
}
}
struct Bar{
Foo!int foo;
}
void main(){
import std.stdio:writeln;
Bar bar = Bar();
auto BAR = new Bar();
writeln(bar, "\t", BAR, "\t", *BAR);
}
```
Did my modifications ensure that this is not treated as a copy
constructor?