www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template fiddling

reply Blonder <andreas schniertshauer.de> writes:
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
parent reply Mafi <mafi example.org> writes:
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,
 Andreas

Hi, 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
parent reply Blonder <andreas schniertshauer.de> writes:
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
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
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.

    

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
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent Blonder <andreas schniertshauer.de> writes:
Thanks a lot  bearophile,  Mafi and  Dmitry Olshansky, this is what I was
looking for.
Aug 08 2010
prev sibling parent Mafi <mafi example.org> writes:
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.

///////////// 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