テンプレートミックスイン
TemplateMixinは、TemplateDeclarationの本体から任意の宣言セットを取り出し、それを挿入する。 を受け取り、それらを現在のコンテキストに挿入する。 を現在のコンテキストに挿入する。
TemplateMixinDeclaration: mixin template Identifier TemplateParameters Constraintopt { DeclDefsopt } TemplateMixin: mixin MixinTemplateName TemplateArgumentsopt Identifieropt ; MixinTemplateName: . MixinQualifiedIdentifier MixinQualifiedIdentifier Typeof . MixinQualifiedIdentifier MixinQualifiedIdentifier: Identifier Identifier . MixinQualifiedIdentifier TemplateInstance . MixinQualifiedIdentifier
TemplateMixinは、モジュールの宣言リストで使うことができる、 クラス、構造体、共用体、またはステートメントとして宣言される。 MixinTemplateNameはTemplateDeclarationまたは TemplateMixinDeclaration を参照しなければならない。 TemplateDeclarationがパラメータを必要としない場合、TemplateArguments は省略できる。
テンプレートのインスタンス化とは異なる、 テンプレートミックスインの本体は、テンプレートのインスタンス化と違って、ミックスインが現れるスコープ内で評価される。 テンプレート宣言が定義されている場所ではなく、ミックスインが現れるスコープ内で評価される。 が定義されている場所ではない。これは、ネストしたスコープにあるmixinの場所に、テンプレートの本体をカット・アンド・ペーストすることに似ている。 テンプレート本体をネストされたスコープのミックスインの位置にカット&ペーストするのと似ている。これは パラメータ化された「定型的な」コードを注入するのに便利である。 テンプレート化されたネストされた関数を作るのにも便利だ。 テンプレートのインスタンス化では必ずしも可能ではない。
int y = 3; mixin template Foo() { int abc() { return y; } } void test() { int y = 8; mixin Foo; // グローバルのyではなくローカルのyがピックアップされる assert(abc() == 8); }
import std.stdio : writeln; mixin template Foo() { int x = 5; } mixin Foo; struct Bar { mixin Foo; } void main() { writeln("x = ", x); // 5を表示する { Bar b; int x = 3; writeln("b.x = ", b.x); // 5を表示する writeln("x = ", x); // 3を表示する { mixin Foo; writeln("x = ", x); // 5を表示する x = 4; writeln("x = ", x); // 4を表示する } writeln("x = ", x); // 3を表示する } writeln("x = ", x); // 5を表示する }
ミックスインのパラメーター
ミックスインは以下のことができる。 パラメータ化できる:
mixin template Foo(T) { T x = 5; } mixin Foo!(int); // int型のxを作成する
ミックスインはシンボルをパラメータ化することができる。 エイリアスパラメータを使う:
mixin template Foo(alias b) { int abc() { return b; } } void test() { int y = 8; mixin Foo!(y); assert(abc() == 8); }
例
この例では、"ミックスイン"を使って、汎用のダフ・デバイスを実装している。 を実装している。 は太字)。ネストされた関数とデリゲート・リテラルが生成される。 これらはコンパイラによってインライン化される:
import std.stdio : writeln; mixin template duffs_device(alias low, alias high, alias fun) { void duff_loop() { if (low < high) { auto n = (high - low + 7) / 8; switch ((high - low) % 8) { case 0: do { fun(); goto case; case 7: fun(); goto case; case 6: fun(); goto case; case 5: fun(); goto case; case 4: fun(); goto case; case 3: fun(); goto case; case 2: fun(); goto case; case 1: fun(); continue; default: assert(0, "Impossible"); } while (--n > 0); } } } } void main() { int i = 1; int j = 11; mixin duffs_device!(i, j, delegate { writeln("foo"); }); duff_loop(); // foo()を10回実行する }
ミックスインのスコープ
ミックスインの宣言は入れ子になったスコープに置かれ、そのスコープを囲むように インポート」される。 スコープに「インポート」される。ミックスイン内の宣言の名前が周囲のスコープにある宣言と同じ場合、その宣言は「インポート」される。 宣言の名前が周囲のスコープにある宣言と同じ場合、周囲の宣言はミックスインの宣言をオーバーライドする。 がミックスインを上書きする:
import std.stdio : writeln; int x = 3; mixin template Foo() { int x = 5; int y = 5; } mixin Foo; int y = 3; void main() { writeln("x = ", x); // 3を表示する writeln("y = ", y); // 3を表示する }
たとえ宣言がオーバーライドされたとしても、ミックスインには独自のスコープがある。 ミックスインは独自のスコープを持つ:
import std.stdio : writeln; int x = 4; mixin template Foo() { int x = 5; int bar() { return x; } } mixin Foo; void main() { writeln("x = ", x); // 4を表示する writeln("bar() = ", bar()); // 5を表示する }
2つの異なるミックスインが同じスコープに置かれ、それぞれが同じ名前の宣言を定義している場合、ミックスインは独自のスコープを持つ。 が同じ名前の宣言を定義している場合、その宣言が参照されたときに曖昧性エラーが発生する エラーが発生する:
import std.stdio : writeln; mixin template Foo() { int x = 5; void func(int x) { } } mixin template Bar() { int x = 4; void func(long x) { } } mixin Foo; mixin Bar; void main() { writeln("x = ", x); // エラー、xがあいまい func(1); // エラー、funcがあいまい }
func() 。 Foo.func とBar.func は異なるスコープにある。
曖昧さを解消する
ミックスインにIdentifierがある場合、それを使って曖昧性を解消することができる。 を使うことができる:
import std.stdio : writeln; int x = 6; mixin template Foo() { int x = 5; int y = 7; void func() { } } mixin template Bar() { int x = 4; void func() { } } mixin Foo F; mixin Bar B; void main() { writeln("y = ", y); // 7を表示する writeln("x = ", x); // 6を表示する writeln("F.x = ", F.x); // 5を表示する writeln("B.x = ", B.x); // 4を表示する F.func(); // Foo.funcを呼び出す B.func(); // Bar.funcを呼び出す }
エイリアス宣言を使って オーバーロード エイリアスの宣言は、異なるミックスインで宣言された関数のオーバーロード・セットを形成するために使用することができる:
mixin template Foo() { void func(int x) { } } mixin template Bar() { void func(long x) { } } mixin Foo!() F; mixin Bar!() B; alias func = F.func; alias func = B.func; void main() { func(1); // B.funcを呼び出す func(1L); // F.funcを呼び出す }
集約型ミックスイン
ミックスインの仮想関数
ミックスインはクラスに仮想関数を追加することができる:
import std.stdio : writeln; mixin template Foo() { void func() { writeln("Foo.func()"); } } class Bar { mixin Foo; } class Code : Bar { override void func() { writeln("Code.func()"); } } void main() { Bar b = new Bar(); b.func(); // Foo.func()を呼び出す b = new Code(); b.func(); // Code.func()を呼び出す }
ミックスイン・デストラクタ
集約型は追加のデストラクタをミックスすることができる。 デストラクタは宣言順とは逆の順序で実行される。
import std.stdio; mixin template addNewDtor() { ~this() { writeln("Mixin dtor"); } } struct S { ~this() { writeln("Struct dtor"); } mixin addNewDtor; } void main() { S s; // `Mixin dtor`を表示する // `Struct dtor`を表示する }
DEEPL APIにより翻訳、ところどころ修正。
このページの最新版(英語)
このページの原文(英語)
翻訳時のdmdのバージョン: 2.108.0
ドキュメントのdmdのバージョン: 2.109.1
翻訳日付 :
HTML生成日時:
編集者: dokutoku