C++のように構造体コピーコンストラクタを明示的に呼び出すことはできますか?D構造体コピーコンストラクタ
struct foo {
void bar() {}
}
foo f;
foo(f).bar();
または私は常にいくつかのvarialbeに新しい値を代入する必要があります。私はこのような何かを書くことができますか?
C++のように構造体コピーコンストラクタを明示的に呼び出すことはできますか?D構造体コピーコンストラクタ
struct foo {
void bar() {}
}
foo f;
foo(f).bar();
または私は常にいくつかのvarialbeに新しい値を代入する必要があります。私はこのような何かを書くことができますか?
技術的には、Dにはコピーコンストラクタもありません。むしろ、構造体は後置のコンストラクタを持つことができます。例えば
struct S
{
this(this)
{
}
}
通常、Dは構造体をできるだけ移動してコピーしようとします。そして、それらをコピーすると、構造体のビット単位のコピーが実行され、ビット単位のコピーを超えて処理が必要な事実の後に構造体を変更するためのポストブライトコンストラクタ(存在する場合)が実行されます。あなたがメンバー
struct S
{
this(this)
{
if(i !is null)
i = new int(*i);
}
int* i;
}
コピーコンストラクタ(C++で)のディープコピーをしたい場合は、/一方で、新しい構造体/クラスを構築し、構造体に対応するメンバのコピーと各メンバーを初期化コピーされるクラス、またはコピーコンストラクタのイニシャライザリストで初期化されたもので置き換えられます。それは、コピーしてからDのポストブラットコンストラクタで起こるように突然変異しません。したがって、コピーコンストラクタと後置コンストラクタは微妙に異なります。
C++のすべてのstructs/classにコピーコンストラクタがありますが(宣言していない場合はコンパイラが常に生成します)、Dのすべての構造体にポストブラットコンストラクタがあるわけではありません。実際、ほとんどの人はそうではありません。コンパイラは、構造体にポストブラストコンストラクタを持つ別の構造体が含まれている場合は構造体を生成します。それ以外の場合は構造体を生成せず、コピーはビット単位のコピーを行います。そして、後置構築がなければ、それを暗黙または明示的に呼び出すことはできません。そのメンバ変数や関数である - 私たちは、この
struct A
{
}
pragma(msg, "A: " ~ __traits(allMembers, A).stringof);
をコンパイルする場合
は今、それはメンバーがない
A: tuple()
A
を印刷します。いずれも宣言されておらず、コンパイラは何も生成していません。
struct B
{
A a;
string s;
}
pragma(msg, "B: " ~ __traits(allMembers, B).stringof);
プリント
B: tuple("a", "s")
それは、二つの部材がある - 明示的に宣言されたメンバ変数を。機能もありません。メンバ変数を宣言しても、コンパイラが関数を生成する理由ではありません。しかし、我々は
struct C
{
this(this)
{
import std.stdio;
writeln("C's postblit");
}
int i;
string s;
}
pragma(msg, "C: " ~ __traits(allMembers, C).stringof);
コンパイルするときに、それだけでなく、その2つのメンバ変数がリストされてい
C: tuple("__postblit", "i", "s", "__xpostblit", "opAssign")
を出力しますが、それはまた、(明示的に宣言postblitコンストラクタがある)だけでなく__xpostblit
とopAssign
として__postblit
を持っています。 __xpostblit
は、コンパイラによって生成されたポストブラットコンストラクタです(それ以上は2番目にあります)。opAssign
は、コンパイラが生成した代入演算子です(C
にはポストブラットコンストラクタがあるため必要です)。それは__xpostblit
なく__postblit
を持っていることを
struct D
{
C[5] sa;
}
pragma(msg, "D: " ~ __traits(allMembers, D).stringof);
プリント
D: tuple("sa", "__xpostblit", "opAssign")
注意。これは、明示的に宣言された後置のコンストラクタを持っていないためです。 __xpostblit
が生成され、各メンバー変数のポストブリークコンストラクターが呼び出されました。 sa
は、C
の静的配列であり、C
は、後置のコンストラクタを持っています。したがって、sa
を正しくコピーするためには、の各要素に対して、C
のポストブリークコンストラクターを呼び出す必要があります。 D
の__xpostblit
です。 C
には__xpostblit
も含まれていますが、後打ちのコンストラクタを持つメンバーはありません。したがって、__xposblit
はその__postblit
を呼び出すだけです。
struct E
{
this(this)
{
import std.stdio;
writeln("E's postblit");
}
C c;
}
pragma(msg, "E: " ~ __traits(allMembers, E).stringof);
プリント
E: tuple("__postblit", "c", "__xpostblit", "opAssign")
ので、E
からC
など - __postblit
と__xpostblit
の両方を持っています。 __postblit
は明示的な後書きコンストラクタであり、__xpostblit
はコンパイラによって生成されたものですが、この場合structは実際には後置コンストラクタを持つメンバ変数を持っていますので、__postblit
を呼び出すよりも__xpostblit
が多くなります。あなたはそれがとても
__posblit:
C's postblit
__xposblit:
C's postblit
印刷し
void main()
{
import std.stdio;
C c;
writeln("__posblit:");
c.__postblit();
writeln("__xposblit:");
c.__xpostblit();
}
ていた場合は、
void main()
{
import std.stdio;
D d;
writeln("__xposblit:");
d.__xpostblit();
}
を持っていた場合、それは
を印刷し、一方、は、2つの間には実質的な違いがありません
__xposblit:
C's postblit
C's postblit
C's postblit
C's postblit
C's postblit
D
のメンバーであるsa
の各要素に対して、C
'postblitが5回呼び出されることに注意してください。また、__postblit
をD
に呼び出すことはできませんでした。なぜなら明示的な後置生成子 - だけが暗黙的なものではないからです。
void main()
{
import std.stdio;
E e;
writeln("__posblit:");
e.__postblit();
writeln("__xposblit:");
e.__xpostblit();
}
は
__posblit:
E's postblit
__xposblit:
C's postblit
E's postblit
を印刷します。この場合には、我々は__postblit
と__xpostblit
が異なっていることがわかります。 __postblit
を呼び出すと明示的に宣言されたポストブリークコンストラクターが呼び出されますが、__xpostblit
はメンバー変数のポストブリーコンストラクターを呼び出します。
そしてA
とB
がposblitコンストラクタとそれらを持っていないメンバーを持っていない、ので、もちろん、彼らに__postblit
または__xpostblit
のいずれかを呼び出すことは違法になります。
したがって、ポストブリーチコンストラクタを明示的に呼び出すことはできますが、それがある場合にのみ、それを呼び出すべきではありません。関数が__
で始まる場合、またはオーバーロードされた演算子の1つで、したがってop
で始まる場合、明示的に呼び出される必要はほとんどありません。また、それには後置のコンストラクタも含まれます。しかし、正当な理由がある場合は、__postblit
ではなく__xpostblit
を呼び出すことを忘れないでください。そうしないと、メンバー変数のポストブリーフは実行されません。 __traits(hasMember, S1, "__xpostblit")
を実行するか、std.traitsから悪い名前のhasElaborateCopyConstructor
を使用してテストすることができます(ほとんどのコードはより慣用的なのでhasElaborateCopyConstructor
を使用する必要があります)。なんらかの理由で__postblit
に電話したい場合は、__postblit
が宣言されているかどうか気にするものがほとんどないので、std.traitsではなく__traits
でテストする必要があります。 posblitコンストラクタを気にするものは、__postblit
が宣言されているかどうかに関係なく、__xpostblit
を気にします。
Dは、それ自体がコピーコンストラクタを持っていませんが、f.tupleof
が与える
foo(f.tupleof).bar()
で(少なくともシャローコピーを作成します)既存の内容に暗黙のコンストラクタを呼び出すことができます関数の引数リストへの自動展開に適した形式の構造体メンバのリスト。