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









Blonder <andreas schniertshauer.de> 