vit:为什么这段代码无法编译?

struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}

this(ref scope typeof(this) rhs){
}
}


struct Bar{
Foo!int foo;
}

void main(){
}
//错误:分段错误(已转储核心)

RazvanN:

问题是​​编译器​​会尝试为​​Bar​​生成大致如下所示的​​inout​​复制构造器:

this(ref scope inout(Bar) p) inout
{
this.foo = p;
}

变形理念是是尽量调用​​Foo​​对象的​​复制构造器​​.问题是​​复制构造器​​与​​(__ctor)​​构造器符号相同,因此变形​​this.foo=p​​为​​foo.__ctor(p)​​.

因为​​实例和参数​​都是​​inout​​,不能调用​​Foo​​的复制构造器,因而调用​​模板构造器​​.生成​​this(scope inout(Foo))inout;​​样的​​构造器​​的​​模板实例​​.它是​​右值构造器​​.不是​​有效代码​​;如果这样:

struct Foo(T){
//this(Rhs, this This)(scope Rhs rhs){}
this(scope inout(Foo!int) rhs) inout {}
this(ref scope typeof(this) rhs){
}
}

将收到不能同时定义​​右值​​和​​复制​​构造器的​​错误消息​​.但,由于是​​模板化​​构造器,在​​实例化​​构造器前,编译器不能​​发出错误​​.有2个​​可能​​修复方法:

(1)重命名​​复制构造器​​为​​__cpCtor​​,这样不会与普通​​构造器重载集​​冲突

(2)​​实例化​​模板构造器时,可检查是否是​​右值​​构造器,并在​​存在​​复制构造器时发出错误.

实现​​复制构造器​​时,我认为​​(1)​​更好,但​​d作者​​坚持要他们有​​相同名称​​.所以,(2)是​​要走​​的路.

Tejas:那​​为什么​​我的修改成功了?

struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}

this(scope Foo!(T)* rhs){
//用 Foo!T替换typeof(this),用指针替换引用.
//保留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);
}

RazvanN:

是的,要通过传递​​ref​​参数来​​显式定义​​复制构造器.因为你期望​​显式指针​​,编译器​​不按​​复制构造器对待,因此不会为​​Bar​​生成​​复制​​构造器.

在此

vit:现在如下工作了:

struct Foo(T){
this(Rhs, this This)(auto ref scope Rhs rhs)
if(__traits(isRef, rhs) == false){
}

this(ref scope typeof(this) rhs){
}
}


struct Bar{
Foo!int foo;
}

void main(){
}

在本地运行它时,它是​​编译时​​​段错误.把​​右值​​​构造器误当作​​复制​​​构造器时,编译器尝试变形​​调用它​​​,但还要复制传递参数,因此它进一步变形为另一个调用​​右值​​​构造器.因此导致无限递归,从而​​栈溢出​​​和​​段错误​​.