模板混入: 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
}