Improve this page
		
	        Github へのログインが必要です。
			簡単な修正は、ここから fork、オンライン編集、pull request ができます。
			大きな修正については、
			通常の clone で行って下さい。
		
	
	
		Page wiki
		
	        関連するWikiページを参照・編集
		
	
	
		English
		
	        このページの英語版(原文)
		
	
  テンプレート・ミックスイン
A TemplateMixin は、 任意の種類の宣言をテンプレートから取り出し、 現在のスコープへ導入します。TemplateMixinDeclaration:
    mixin template TemplateIdentifier ( TemplateParameterList ) Constraintopt
	    { DeclDefs }
TemplateMixin:
    mixin TemplateIdentifier ;
    mixin TemplateIdentifier MixinIdentifier ;
    mixin TemplateIdentifier !( TemplateArgumentList ) ;
    mixin TemplateIdentifier !( TemplateArgumentList ) MixinIdentifier ;
MixinIdentifier:
    Identifier
        TemplateMixin は、モジュール、クラス、構造体、共用体の宣言リストの途中や、 あるいは一つの文としての位置に書くことができます。 TemplateIdentifier は TemplateDeclaration を参照します。 もしテンプレートが引数を取らないのであれば、 !(TemplateArgumentList) を省略した形式で書いても構いません。
テンプレートのインスタンス化とは異なり、テンプレートのmixinの本体は、 テンプレート定義のあるスコープではなく、mixinされた先のスコープの中で評価されます。 これは、テンプレートの本体をカット&ペーストして mixin したい場所に貼り付けるのと似た動作と言えるでしょう。 この機能は、パラメタ抽象された ‘boilerplate’ コードを挿入するのにはもちろん、 ただのインスタンス化では不可能な、 テンプレートネスト関数の作成にも役立ちます。
mixin template Foo() {
  int x = 5;
}
mixin Foo;
struct Bar {
  mixin Foo;
}
void test() {
  writefln("x = %d", x);  // 5 を表示
  {
    Bar b;
    int x = 3;
    writefln("b.x = %d", b.x); // 5 を表示
    writefln("x = %d", x);     // 3 を表示
    {
      mixin Foo;
      writefln("x = %d", x);   // 5 を表示
      x = 4;
      writefln("x = %d", x);   // 4 を表示
    }
    writefln("x = %d", x);     // 3 を表示
  }
  writefln("x = %d", x);       // 5 を表示
}
	Mixinはパラメタ化することができます:
mixin template Foo(T) {
  T x = 5;
}
mixin Foo!(int);           // int型変数xを作成
	クラスに仮想関数を付け加えることも可能です:
mixin template Foo() {
  void func() { writefln("Foo.func()"); }
}
class Bar {
  mixin Foo;
}
class Code : Bar {
  override void func() { writefln("Code.func()"); }
}
void test() {
  Bar b = new Bar();
  b.func();      // calls Foo.func()
  b = new Code();
  b.func();      // calls Code.func()
}
	Mixin は、テンプレート宣言のあるスコープではなく、
	mixin が現れたスコープにおいて評価されます:
int y = 3;
mixin template Foo() {
  int abc() { return y; }
}
void test() {
  int y = 8;
  mixin Foo; // ローカルの y が選ばれる。グローバルの y ではなく。
  assert(abc() == 8);
}
	alias引数を使うと、シンボルをパラメタに取ることができます:
mixin template Foo(alias b) {
  int abc() { return b; }
}
void test() {
  int y = 8;
  mixin Foo!(y);
  assert(abc() == 8);
}
	以下の例は、任意の文に対して使える汎用の"ダフのデバイス"を実装するのに
	Mixin を使っています。(この例の場合、任意の文にできる箇所を太字で表記しています。)
	ネストした関数もdelegateリテラルで同様に生成することができますし、
	これらはコンパイラによるインライン化が見込めます:
mixin 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(); goto case;
        case 7:      s(); goto case;
        case 6:      s(); goto case;
        case 5:      s(); goto case;
        case 4:      s(); goto case;
        case 3:      s(); goto case;
        case 2:      s(); goto case;
        case 1:      s(); continue;
        default:     assert(0, "Impossible");
                } while (--n > 0);
      }
    }
  }
}
void foo() { writefln("foo"); }
void test() {
  int i = 1;
  int j = 11;
  mixin duffs_device!(i, j, delegate { foo(); } );
  duff_loop();  // foo() を10回実行
}
ミックスインのスコープ
Mixinの中の宣言は、周囲のスコープに ‘import’ されます。 Mixinの中の宣言と同じ名前の宣言が周囲のスコープに存在した場合、 周囲のスコープの宣言が、 Mixinのそれを上書きします:int x = 3;
mixin template Foo() {
  int x = 5;
  int y = 5;
}
mixin Foo;
int y = 3;
void test() {
  writefln("x = %d", x);  // 3 を表示
  writefln("y = %d", y);  // 3 を表示
}
	二つの異なるMixinが同じスコープへ置かれて、
	しかもおのおのが同名の宣言を行っている場合、
	その宣言を参照すると曖昧さのためエラーになります:
mixin template Foo() {
  int x = 5;
  void func(int x) { }
}
mixin template Bar() {
  int x = 4;
  void func() { }
}
mixin Foo;
mixin Bar;
void test() {
  writefln("x = %d", x); // エラー、x は曖昧
  func();             // エラー、func は曖昧
}
        この func() の呼び出しが曖昧とされるのは、 Foo.func と Bar.func が異なるスコープにあるからです。
mixin 宣言に MixinIdentifier が指定されていれば、 それを使って曖昧さを解消できます:
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 test() {
  writefln("y = %d", y);     // 7 を表示
  writefln("x = %d", x);     // 6 を表示
  writefln("F.x = %d", F.x); // 5 を表示
  writefln("B.x = %d", B.x); // 4 を表示
  F.func();                  // Foo.func を呼ぶ
  B.func();                  // Bar.func を呼ぶ
}
        alias宣言を使って、 違うmixinで宣言された関数をオーバーロードすることは可能です:
mixin template Foo() {
  void func(int x) {  }
}
mixin template Bar() {
  void func() {  }
}
mixin Foo!() F;
mixin Bar!() B;
alias F.func func;
alias B.func func;
void main() {
  func();  // B.func を呼び出す
  func(1); // F.func を呼び出す
}
        宣言は周囲のもので上書きされますが、 mixinの内部では、それ自身の独自のスコープを持ちます。
int x = 4;
mixin template Foo() {
  int x = 5;
  int bar() { return x; }
}
mixin Foo;
void test() {
  writefln("x = %d", x);         // 4 を表示
  writefln("bar() = %d", bar()); // 5 を表示
}
  
 D Programming Language
		D Programming Language