fork download
  1. /*
  2. D言語 2012/1/20
  3. D言語の機能、mixinとタプルについて。
  4.  
  5. 1. ミックスイン
  6. mixin(string src);
  7. とすることで、srcをソースコードに含めることができる。
  8.  
  9. Example: */ /+
  10. import std.stdio;
  11. void main(){
  12. mixin("int a = 123");
  13. wirteln(a); //123と表示
  14. }
  15. +/ /*
  16.  
  17. 2. テンプレート・ミックスイン
  18. mixin template Name
  19. と書かれたテンプレートを
  20. mixin Name
  21. とすることで、そのソースコードにNameの中身を含めることができる。
  22. スコープはそこに入る。
  23.  
  24. Example: */ /+
  25. import std.stdio;
  26. mixin template hogehogehoge(){
  27. string a = "Hello D World";
  28. }
  29. void main(){
  30. mixin hogehogehoge;
  31. writeln(a); //"Hello D World"と表示
  32. }
  33. +/ /*
  34.  
  35. 3. タプル
  36. タプルとは、Haskellなどに実装されている機能で、D言語にも存在する。
  37. タプルの幾つかの機能は言語組み込みで、その他の機能はstd.typeconsやstd.typetupleが提供している。
  38. タプルには次の三種類がある。
  39. 1.型タプル
  40. 型タプルは */ /+
  41. Tuple!(int,long,real)
  42. +/ /* というように宣言され、要素に型をもつものである。
  43.  
  44. 2.式タプル
  45. 式タプルは */ /+
  46. Tuple!("hello","world",1,2,3,4,5)
  47. +/ /* というように宣言されたものである。
  48.  
  49. 3.値タプル
  50. */ /+ Tuple!(fuga,hoge,hoge) foo; +/ /*
  51. というようにタプル型で宣言された変数fooを値タプルという。
  52. 値タプルはC言語の構造体のようなもので、fuga型の値とhoge型とhoge型の値を格納できる。
  53. しかしC言語の構造体と違うのは配列同様にアクセスでき、スライスできることである。
  54. 式タプルとの違いは、式タプルは値はstaticでコンパイル時に決定されるが、値タプルは変数であるので実行時に変更が可能な点である。
  55.  
  56. ※型タプルと式タプルは混合することができる。
  57.  
  58. 型タプルと式タプルはテンプレートの可変長個引数 */ /+
  59. template Tuple(E...){
  60. alias E Tuple;
  61. } +/ /*
  62. のE...の部分で作られる。
  63. たとえば *//+
  64. Tuple!(int,"hello",long,"world") +/ /*
  65. とすれば、E[0]はint、E[1]は"hello"、E[2]はlong、E[3]は"world"のように格納される。
  66. さらにタプルは結合やスライスが言語組み込みの機能として動く。
  67. たとえば */ /+
  68. Tuple!(Tuple!(int,int),Tuple!(long,long))[0..3] +/ /*
  69. は、 */ /+
  70. Tuple!(int,int,long) +/ /*
  71. に等しい。
  72. さらにタプルはforeach文でループを回すことができる。(for文では回せない)
  73. タプルがあることにより、D言語のテンプレートは可変長個引数を取れ、さらにスライスとインデックス演算子により再帰的なテンプレート宣言を可能としている。
  74. 通常はstd.typeconsやstd.typetupleをインポートしてしまえばtemplate Tupleは宣言せずに使えるが、今回はインポートせずあえてtemplate Tuple(E...)を定義した。
  75.  
  76. 以上3つの機能を使うことによりC++言語では到底かなわないようなテンプレートメタプログラミングが可能である。
  77. 今回はベクトルチックな構造体をテンプレートメタプログラミングで作成してみたい。
  78. */
  79.  
  80. import std.stdio;
  81.  
  82. ///タプルの作成
  83. template Tuple(E...){
  84. alias E Tuple;
  85. }
  86.  
  87. ///構造体内部の値の作成
  88. template valuecreate(int N,string label,E...){
  89. static if(E.length > 1) //再帰的に処理する。
  90. immutable valuecreate = E[0].stringof ~ " " ~ label ~ N.stringof ~ ";" ~ valuecreate!(N+1,label,E[1..$]);
  91. else static if(E.length == 1)
  92. immutable valuecreate = E[0].stringof ~ " " ~ label ~ N.stringof ~ ";";
  93. else
  94. static assert(0);
  95. }
  96.  
  97. ///構造体を作成
  98. mixin template StructCreate(string label,string valuelabel,E...){
  99. mixin("struct "~label~"{public:"~valuecreate!(0,valuelabel,E)~"\n"~GenerateOpBinary!(label,valuelabel,E.length-1)~"\nalias Tuple!"~E.stringof~" tuple;"~"}");
  100. }
  101.  
  102. ///二項演算子を作りあげる
  103. template GenerateOpBinary(string label,string valuelabel,int N){
  104. immutable GenerateOpBinary = label~" opBinary(string s)("~label~" src){\n"~
  105. label~" dst;\n"
  106. ~GenerateOpBinary_Sub!(valuelabel,N)~
  107. "return dst;\n}\n";
  108. }
  109.  
  110. ///二項演算子の中身を作りあげる。
  111. template GenerateOpBinary_Sub(string valuelabel,int N){
  112. static if(N > 0)
  113. immutable GenerateOpBinary_Sub = "mixin(\" dst."~valuelabel~N.stringof~"="~valuelabel~N.stringof~"\"~s~\" src."
  114. ~valuelabel~N.stringof~";\");\n"~GenerateOpBinary_Sub!(valuelabel,N-1);
  115. else static if(N == 0)
  116. immutable GenerateOpBinary_Sub = "mixin(\"dst."~valuelabel~N.stringof~"="~valuelabel~N.stringof~"\"~s~\" src."
  117. ~valuelabel~N.stringof~";\");\n";
  118. else
  119. static assert(0);
  120. }
  121.  
  122. void main(){
  123. mixin("int a = 512;"); //文字列mixin
  124. writeln(a);
  125.  
  126. //構造体hogeはint,real,longをそれぞれval_0,val_1,val_2というメンバーとして持ち、二項演算子が定義された構造体
  127. mixin StructCreate!("hoge","val_",int,real,long);
  128.  
  129. hoge bar1,bar2,bar3;
  130.  
  131. bar1.val_0 = 8;
  132. bar1.val_1 = 11;
  133. bar1.val_2 = 12;
  134.  
  135. bar2.val_0 = 12;
  136. bar2.val_1 = 19;
  137. bar2.val_2 = 28;
  138.  
  139. writeln(bar1+bar2); //ベクトル和(数学と同じ)
  140. writeln(bar1-bar2); //ベクトル差(数学と同じ)
  141. writeln(bar1*bar2); //プログラムでいうベクトル積(数学とは違う)
  142. writeln(bar1%bar2); //プログラムでいうベクトル剰余演算(数学とは違う)
  143.  
  144. //浮動小数点数と虚数と複素数とhogeをもつ4(6)次元ベクトルを作成。
  145. mixin StructCreate!("fuga","val_",real,ireal,creal,hoge);
  146.  
  147. fuga foo1,foo2;
  148. foo1.val_0 = 12.3;
  149. foo1.val_1 = 12.3i;
  150. foo1.val_2 = 12.3 + 12.3i;
  151. foo1.val_3.val_0 = 12;
  152. foo1.val_3.val_1 = 19;
  153. foo1.val_3.val_2 = 120;
  154.  
  155. foo2 = foo1;
  156. writeln(foo1+foo2);
  157.  
  158. //9次元ベクトルを作成。 fuga.tupleとhoge.tupleは構造体内部の型のタプルを返すように定義している。
  159. mixin StructCreate!("DDDreland","val_",fuga.tuple,hoge.tuple);
  160. DDDreland Dr1,Dr2;
  161. Dr1.val_0 = 12.3;
  162. Dr1.val_1 = 12.3i;
  163. Dr1.val_2 = 12.3 + 12.3i;
  164. Dr1.val_3.val_0 = 12;
  165. Dr1.val_3.val_1 = 19;
  166. Dr1.val_3.val_2 = 120;
  167. Dr1.val_4 = 8;
  168. Dr1.val_5 = 11;
  169. Dr1.val_6 = 12;
  170.  
  171. Dr2 = Dr1;
  172. writeln(Dr2+Dr1);
  173. }
Success #stdin #stdout 0.02s 2136KB
stdin
Standard input is empty
stdout
512
hoge(20, 30, 40)
hoge(-4, -8, -16)
hoge(96, 209, 336)
hoge(8, 11, 12)
fuga(24.6, 24.6i, 24.6+24.6i, hoge(24, 38, 240))
DDDreland(24.6, 24.6i, 24.6+24.6i, hoge(24, 38, 240), 16, 22, 24)