digitalmars.D.learn - template fiddling
- Blonder (30/30) Aug 07 2010 Hello,
- Mafi (25/55) Aug 07 2010 Hi,
- Blonder (9/9) Aug 07 2010 Hello,
- Dmitry Olshansky (19/30) Aug 07 2010 Probably, this could be a starting point (BTW In D you can write
- bearophile (116/134) Aug 07 2010 I have added another version:
- Blonder (1/1) Aug 08 2010 Thanks a lot @bearophile, @Mafi and @Dmitry Olshansky, this is what I wa...
- Mafi (31/40) Aug 07 2010 Is that what you are searching for:
Hello, I am trying to understand the template mechanism in D, but I don't get it working. I want to compute the dot product as follows: int[] a = [1, 2, 3]; int[] b = [5, 6, 7]; double dd = ???.dot_product( a, b ); with classes like this: class DotProduct(DIM, T) { static T result(T a, T b) { return a * b + DotProduct!(DIM-1, T).result(a+1, b+1); } } class DotProduct(1, T) { static T result(T a, T b) { return a * b; } } and a function : T dot_product(DIM a, T b) { return ???.result( a, b ); } Can anyone help me? In C++ its not the problem but with D I can't get it working. Thanks, Andreas
Aug 07 2010
Am 07.08.2010 18:40, schrieb Blonder:Hello, I am trying to understand the template mechanism in D, but I don't get it working. I want to compute the dot product as follows: int[] a = [1, 2, 3]; int[] b = [5, 6, 7]; double dd = ???.dot_product( a, b ); with classes like this: class DotProduct(DIM, T) { static T result(T a, T b) { return a * b + DotProduct!(DIM-1, T).result(a+1, b+1); } } class DotProduct(1, T) { static T result(T a, T b) { return a * b; } } and a function : T dot_product(DIM a, T b) { return ???.result( a, b ); } Can anyone help me? In C++ its not the problem but with D I can't get it working. Thanks, AndreasHi, to make an instance of an template you use the !-infix operator: 'template!(param,...)'. If you want to give only one parameter you can use 'template!param'. But your example can't work because template arguments have to be evaluatable at compile time (which function parameters are not). You can use a normal function parameter. In your example you use a template class which isn't supposed to be used as class, I think. If so, you should make a simple template template MyTemplate(.......){ int myFunction(....){} int myFunction2(....){} } Then you can say MyTemplate!(...).myFunction(...). You can leave out tralling template arguments which deducable by the arguments of the function. There also a trick that you can use to make a shortcut. Add alias MyTemplate myFunction to the template. Then you can use MyTemplate!(....)(....)instead of MyTemplate!(.....).myFunction(....). MyTemplate!(....).myFunction2(....) will still work. The above trick is also how class and function templates work. Mafi P.S. If you often use some template instance you can use an alias alias MyTemplate!(.....) MyInstance
Aug 07 2010
Hello, the template!(...) mechanism I understand. But I think I need the two classes, the first is the primary template and the second the partial specialization (this is the end of the "loop"), or can I do this in D with functions? The normal computation of the dot product is normally done in a for loop. But with templates you can enroll the loop. template!(...)(3, a, b). In this example 3 is the dimension of the arrays a and b. Andreas.
Aug 07 2010
On 07.08.2010 23:04, Blonder wrote:Hello, the template!(...) mechanism I understand. But I think I need the two classes, the first is the primary template and the second the partial specialization (this is the end of the "loop"), or can I do this in D with functions? The normal computation of the dot product is normally done in a for loop. But with templates you can enroll the loop. template!(...)(3, a, b). In this example 3 is the dimension of the arrays a and b.Probably, this could be a starting point (BTW In D you can write templates very easy): T dot_product(size_t N, T)(T[] a, T[] b){ static if (N == 1){ return a[0] * b[0]; }else{ return a[0] * b[0] + dot_product!(N-1)(a[1..$],b[1..$]); } } void main() { int[] a = [1, 2, 3]; int[] b = [5, 6, 7]; assert( dot_product!3(a,b) == 38 );//sanity check } And I didn't checked the disassembly.Andreas.-- Dmitry Olshansky
Aug 07 2010
Dmitry Olshansky:Probably, this could be a starting point (BTW In D you can write templates very easy): T dot_product(size_t N, T)(T[] a, T[] b){ static if (N == 1){ return a[0] * b[0]; }else{ return a[0] * b[0] + dot_product!(N-1)(a[1..$],b[1..$]); } } void main() { int[] a = [1, 2, 3]; int[] b = [5, 6, 7]; assert( dot_product!3(a,b) == 38 );//sanity check } And I didn't checked the disassembly.I have added another version: import std.typetuple: TypeTuple; T dot_product(size_t N, T)(T[] a, T[] b) { static if (N == 1) return a[0] * b[0]; else return a[0] * b[0] + dot_product!(N-1)(a[1..$],b[1..$]); } template Iota(int stop) { static if (stop <= 0) alias TypeTuple!() Iota; else alias TypeTuple!(Iota!(stop-1), stop-1) Iota; } T dotProduct(T, int N)(T[N] a, T[N] b) { T result = 0; foreach (i; Iota!(N)) result += a[i] * b[i]; return result; } void main() { double[3] a = [1., 2., 3.]; double[3] b = [5., 6., 7.]; assert(dot_product!3(a, b) == 38.0); assert(dotProduct(a, b) == 38.0); } The asm (dmd 2.047 -O -release -inline): _D6test6b22__T11dot_productVi3TdZ11dot_productFAdAdZd comdat sub ESP,038h mov EDX,048h[ESP] mov EAX,044h[ESP] push EBX mov ECX,044h[ESP] mov EBX,048h[ESP] push ESI dec EBX mov ESI,044h[ESP] mov 8[ESP],EBX dec ESI mov EAX,044h[ESP] mov 010h[ESP],ESI mov EAX,8[ESP] mov EBX,010h[ESP] dec EBX dec EAX fld qword ptr [EDX] lea EDX,8[EDX] fmul qword ptr [ECX] lea ECX,8[ECX] mov 0Ch[ESP],EDX mov 014h[ESP],ECX fld qword ptr [EDX] lea EDX,8[EDX] fmul qword ptr [ECX] lea ECX,8[ECX] fld qword ptr [EDX] fmul qword ptr [ECX] faddp ST(1),ST faddp ST(1),ST pop ESI pop EBX add ESP,038h ret 010h _D6test6b22__T11dot_productVk2TdZ11dot_productFAdAdZd comdat sub ESP,018h mov EDX,028h[ESP] mov EAX,024h[ESP] push EBX mov ECX,024h[ESP] mov EBX,028h[ESP] push ESI mov ESI,024h[ESP] mov EAX,024h[ESP] dec ESI dec EBX fld qword ptr [EDX] lea EDX,8[EDX] fmul qword ptr [ECX] lea ECX,8[ECX] fld qword ptr [EDX] fmul qword ptr [ECX] faddp ST(1),ST pop ESI pop EBX add ESP,018h ret 010h _D6test6b22__T11dot_productVk1TdZ11dot_productFAdAdZd comdat mov EDX,010h[ESP] mov EAX,0Ch[ESP] mov EAX,4[ESP] fld qword ptr [EDX] mov EDX,8[ESP] fmul qword ptr [EDX] ret 010h _D6test6b21__T10dotProductTdVk3Z10dotProductFG3dG3dZd comdat sub ESP,048h fld qword ptr 064h[ESP] fmul qword ptr 04Ch[ESP] fldz faddp ST(1),ST fstp qword ptr [ESP] fld qword ptr 06Ch[ESP] fld qword ptr 074h[ESP] fxch ST1 fmul qword ptr 054h[ESP] fxch ST1 fmul qword ptr 05Ch[ESP] faddp ST(1),ST fadd qword ptr [ESP] fstp qword ptr [ESP] fld qword ptr [ESP] add ESP,048h ret 030h Bye, bearophile
Aug 07 2010
Thanks a lot bearophile, Mafi and Dmitry Olshansky, this is what I was looking for.
Aug 08 2010
Am 07.08.2010 21:04, schrieb Blonder:Hello, the template!(...) mechanism I understand. But I think I need the two classes, the first is the primary template and the second the partial specialization (this is the end of the "loop"), or can I do this in D with functions? The normal computation of the dot product is normally done in a for loop. But with templates you can enroll the loop. template!(...)(3, a, b). In this example 3 is the dimension of the arrays a and b. Andreas.Is that what you are searching for: ///////////// module templatetest; import std.stdio; T[] foo(T : T[], int S) (T[] t) { writeln("Hey ",S); return foo!(T[],S-1)(t); } T[] foo(T : T[], int S : 0) (T[] t) { writeln("END"); return(t); } /* //Can't get static arrays right //always uses dynamic version T[S] foo(T : T[S], int S) (T[S] t) { writeln("Hello ",S); return foo!(T[],S-1)(t); } T[S] foo(T : T[S], int S:0) (T[S] t) { writeln("END2"); }*/ void main() { int[] x = [25,42,26,34,10]; foo!(int[],5)(x); } ////////////// Uage foo!(int[],5)(xy). If you swap around the array parameters in your version then you should be able to omit T. Also when you have fixed-size arrays the array length isn't DRY.
Aug 07 2010