## 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:
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
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
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
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.

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

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):

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]
pop	ESI
pop	EBX
ret	010h

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]
pop	ESI
pop	EBX
ret	010h

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
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]
fstp	qword ptr [ESP]
fld	qword ptr [ESP]
ret	030h

Bye,
bearophile
```
Aug 07 2010
Blonder <andreas schniertshauer.de> writes:
```Thanks a lot  bearophile,  Mafi and  Dmitry Olshansky, this is what I was
looking for.
```
Aug 08 2010
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.

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