On 02/14/2012 03:36 PM, Marco Leise wrote:
Am 14.02.2012, 13:32 Uhr, schrieb bearophile <[email protected]>:

Any way, the post was mostly about the @templated() (and not much
about the not so useful "static static" idea), that's useful when you
define a class template or struct template on several template
arguments, and some of its methods use only a subset of the template
arguments.

Bye,
bearophile

I was thinking that "@templated(...)" isn't necessary, since it can be
deduced naturally from the used symbols inside the
function/template/etc. to the end that it would just be a compiler
optimization.

1. Use all template arguments as usual (in this case of the
struct/class) for generating the inner template (a method in this case)
2. While generating the method, keep track of used templated symbols
from the outer scope.
3. For later reference, tag the generated method with template arguments
introduced by the symbols from step 2.

This can yield sets like those for a struct with 3 template arguments
and an imaginary method:
char, 5, int // for "Foo!(char, 5, int)
char, 3, int // for "Foo!(char, 3, int)
char, 1 // for "Foo!(char, 1, int)
The last case shows, that a "static if" inside the templated method
caused the third argument to be ignored. The next time, the compiler
sees the method template instantiated for (char, 1, ubyte), it will
match this with the existing tag (char, 1).

To illustrate that I have this struct here:

struct Foo(U, V, W) {
W idx;
union {
U[] arr;
U noarr;
}
U bar() {
static if (V == 1) {
return noarr;
} else {
return arr[idx]; // idx of templated type 'W' is introduced
}
}
W get_idx() { // uses only symbols of type 'W'
return idx; // no need to template on 'U' & 'V'
}
}

It cannot be a compiler optimization because it potentially changes the semantics of the code:

template T(U, V, W){
    @templated(W) W idx;
}

void main(){
    T!(int,double,long).idx = 1;
    assert(T!(double,int,long).idx == 1);
}

Reply via email to