模板混入: mixin 模板標志符 ; mixin 模板標志符 混入標志符 ; mixin 模板標志符 !( 模版參數列表 ) ; mixin 模板標志符 !( 模版參數列表 ) 混入標志符 ; 混入標志符: 標志符
TemplateMixin: mixin TemplateIdentifIEr ; mixin TemplateIdentifIEr MixinIdentifIEr ; mixin TemplateIdentifIEr !( TemplateArgumentList ) ; mixin TemplateIdentifIEr !( TemplateArgumentList ) MixinIdentifIEr ; MixinIdentifIEr: IdentifIEr模版混入 可以出現在模塊、類、結構、聯合以及語句的聲明列表中。模板標志符 是一個 模版聲明 。如果 模版聲明 沒有參數,就可以使用不帶 !(模版參數列表) 的混入形式。
不像模板具現化,模板混入的過程體在混入所在的作用域內計算,而不是在定義模板聲明的地方。這等價於使用剪切和粘貼將模版的過程體插入混入的位置。這對注入參數化的‘樣板文件’是有用的,同時對創建模板化嵌套函數也很有用,而正常情況下是不可能具現化嵌套函數的。
template Foo() { int x = 5; } mixin Foo; struct Bar { mixin Foo; } void test() { printf("x = %d\n", x); // 打印出 5 {
Bar b; int x = 3; printf("b.x = %d\n", b.x); // 打印出 5 printf("x = %d\n", x); // 打印出 3 { mixin Foo; printf("x = %d\n", x); // 打印出 5 x = 4; printf("x = %d\n", x); // 打印出 4 } printf("x = %d\n", x); // 打印出 3 } printf("x = %d\n", x); // 打印出 5 }混入可以被參數化:
template Foo(T) { T x = 5; } mixin Foo!(int); // 創建類型為 int 的 x混入可以可以為類添加虛函數:
template Foo() { void func() { printf("Foo.func()\n"); } } class Bar { mixin Foo; } class Code : Bar { void func() { printf("Code.func()\n"); } } void test() { Bar b = new Bar(); b.func(); // 調用 Foo.func() b = new Code(); b.func(); // 調用 Code.func() }混入在它們出現的地方被求值,而不是在模板聲明的地方:
int y = 3; template Foo() { int abc() { return y; } } void test() { int y = 8; mixin Foo; // 使用的是局部的 y ,而不是全局的 y assert(abc() == 8); }混入可以使用別名參數來參數化符號:
template Foo(alias b) { int abc() { return b; } } void test() { int y = 8; mixin Foo!(y); assert(abc() == 8); }這個例子使用了一個混入來為任意語句實現一個泛型 Duff's Device(在這裡,那個語句采用粗體表示)。在生成一個嵌套函數的同時也生成了一個委托文字量,他們會通過編譯器內聯:
template duffs_device(alias id1, alias id2, alias s) { void duff_loop() { if (id1 < id2) { typeof(id1) n = (id2 - id1 + 7) / 8; switch ((id2 - id1) % 8) { case 0: do { s(); case 7: s(); case 6: s(); case 5: s(); case 4: s(); case 3: s(); case 2: s(); case 1: s(); } while (--n > 0); } } } } void foo() { printf("foo\n"); } void test() { int i = 1; int j = 11; mixin duffs_device!(i, j, delegate { foo(); } ); duff_loop(); // 執行 foo() 10 次 }混入作用域
混入中的聲明被‘導入’到周圍的作用域中。如果混入和其周圍的作用域中有相同的名字,周圍的作用域中的聲明將覆蓋混入中的那個聲明:int x = 3; template Foo() { int x = 5; int y = 5; } mixin Foo; int y = 3; void test() { printf("x = %d\n", x); // 打印出 3 printf("y = %d\n", y); // 打印出 3 }如果兩個不同的混入被放入同一個作用域,並且他們中定義了同名的聲明,就會出現模稜兩可的錯誤:如果一個混入中有 混入標志符 ,它可以用來消除歧義:template Foo()
{
int x = 5;
}
template Bar()
{
int x = 4;
}
mixin Foo;
mixin Bar;
void test()
{
printf("x = %d\n", x); // 錯誤,x 模稜兩可
}int x = 6; template Foo() { int x = 5; int y = 7; } template Bar() { int x = 4; } mixin Foo F; mixin Bar B; void test() { printf("y = %d\n", y); // 打印出 7 printf("x = %d\n", x); // 打印出 6 printf("F.x = %d\n", F.x); // 打印出 5 printf("B.x = %d\n", B.x); // 打印出 4 }混入有其自身的作用域,盡管聲明會被外圍的聲明覆蓋:int x = 4; template Foo() { int x = 5; int bar() { return x; } } mixin Foo; void test() { printf("x = %d\n", x); // 打印出 4 printf("bar() = %d\n", bar()); // 打印出 5 }