テンプレートメタプログラミング

C++ の強力な能力の一端を担っているのがテンプレートでしょう.

しかし, 無理な拡張のせいか構文にも無理があったりする.

D 言語のテンプレートは C++ よりも洗練されており, 構文も整理されている.

関数テンプレート

template.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import std.stdio;

template Max(T){
  T max(T lhs, T rhs){
    if (lhs > rhs)
      return lhs;
    else
      return rhs;
  }
}

// alias Max!(int) IntMax;

void main(){
  int r = Max!(int).max(10, 20);
/*
  明示的なインスタンス化は, テンプレート名!(型名) と書く.
  インスタンス化したテンプレートに別名を付けることもできる.
  alias Max!(int) IntMax;
  int r = IntMax.max(10, 20);
*/
  writeln("Max!(int).max(10, 20) = ", r);  
}

template.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./template
Max!(int).max(10, 20) = 20

template2.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import std.stdio;

T max(T)(T lhs, T rhs){
    if (lhs > rhs)
      return lhs;
    else
      return rhs;
  }

void main(){
  int r = max!(int)(10, 20);
  // int r = max(10, 20);
/*
  テンプレートパラメータ が一つだけのときは ! の後の () を省略できる
  max!(int) は max!int と等価
  関数テンプレートのテンプレート引数は, 与えられた引数の型から推論できるとき,
  省略できる.
  int r = max(10, 20);
*/
  writeln("max!(int).max(10, 20) = ", r);  
}

template2.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./template2
max!(int).max(10, 20) = 20

メンバ関数テンプレート

member_temp.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import std.stdio;

class SizeOf{
  bool comp(T, U)(T lhs, U rhs){
    return (lhs.sizeof == rhs.sizeof);
  }
}

void main(){
  SizeOf x = new SizeOf;
  writeln( x. comp(1, 2) );
  writeln( x. comp(1, '2') );
}

member_temp.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./member_temp
true
false

クラステンプレート

class_temp.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import std.stdio;

template Calc(T){
  class Adder{
    T add(T lhs, T rhs){
      return lhs + rhs;
    }
  }
}

void main(){
  Calc!(int).Adder x = new Calc!(int).Adder;
  writeln( x.add(10, 20) );
/*
  alias で別名を付ける場合
  alias Calc!(int) IntCalc;
  IntCalc.Adder x = new IntCalc.Adder;
*/
/*
  クラスまで含めて別名をつけるなら
  alias Calc!(double).Adder DoubleAdder;
  DoubleAdder y = new DoubleAdder;
*/  
}

class_temp.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./class_temp
30

関数テンプレートと同様の省略記法が使える.

class_temp2.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import std.stdio;

class Adder(T){
  T add(T lhs, T rhs){
    return lhs + rhs;
  }
}

void main(){
  Adder!(int) x = new Adder!(int);
  // Adder!int x = new Adder!int; // このように, () を省略できる
  writeln( x.add(10, 20) );
}

class_temp2.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./class_temp2
30

テンプレートの特殊化

C++ でのテンプレートの特殊化と同様のことが D でもできる.

temp.d

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import std.stdio;

void f(T)(T t){
  writeln(t);
}

void f(T:int)(T t){ // T が int のときはこちらの実装が使われる
  writeln(t, " is int");
}

void main(){
  f("hoge");
  f(123);
}

temp.d の実行結果は:

[cactus:~/code_d/d_tuts]% ./temp
hoge
123 is int

Table Of Contents

Previous topic

RAII

Next topic

ref 関数