Strange alias behaviour in template arguments

anonymous via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Mar 3 06:40:42 PST 2015


On Tuesday, 3 March 2015 at 13:42:09 UTC, Stefan Frijters wrote:
> So this is a strange thing I ran into while trying to 
> streamline some templates in my code, where fixed-length arrays 
> are passed as runtime arguments. I started out by trying 
> variant fun2(), which disappointingly didn't work. fun3() then 
> did its job but I was suspicious and tried fun4() and fun(5), 
> which also worked but shouldn't. Is this a bug or am I doing 
> something bad?
>
> struct Connectivity(uint _d, uint _q) {
>   enum d = _d; // Number of dimensions
>   enum q = _q;
> }
>
> alias d2q9 = Connectivity!(2,9);
>
> // Stores fixed-size array of base type T, and the length of 
> the array is determined by the connectivity.
> struct Field(T, alias c) {
>   alias conn = c;
>   T[conn.d] payload;
>
>   this(in T[conn.d] stuff) {
>     payload = stuff;
>   }
> }
>
> // Ok
> void fun(T)(T field) {
>   pragma(msg, T);
>   pragma(msg, T.conn);
>   pragma(msg, T.conn.d);
>   pragma(msg, T.conn.q);
> }
>
> // cannot deduce function from argument types
> void fun2(T)(T field, double[T.conn.d] foo) {
>   pragma(msg, T);
>   pragma(msg, T.conn);
>   pragma(msg, T.conn.d);
>   pragma(msg, T.conn.q);
>   field.payload = foo;
> }
>
> // Ok!
> void fun3(T, alias d = T.conn.d)(T field, double[d] foo) {
>   pragma(msg, T);
>   pragma(msg, T.conn);
>   pragma(msg, T.conn.d);
>   pragma(msg, T.conn.q);
>   pragma(msg, typeof(foo)); // 2, okay
>   field.payload = foo;
> }
>
> // Huh?
> void fun4(T, alias d = T.conn.q)(T field, double[d] foo) {
>   pragma(msg, T);
>   pragma(msg, T.conn);
>   pragma(msg, T.conn.d);
>   pragma(msg, T.conn.q);
>   pragma(msg, typeof(foo)); // expect 9, get 2
>   field.payload = foo;
> }
>
> // Huh?
> void fun5(T, alias d = T.conn)(T field, double[d] foo) {
>   pragma(msg, T);
>   pragma(msg, T.conn);
>   pragma(msg, T.conn.d);
>   pragma(msg, T.conn.q);
>   pragma(msg, typeof(foo)); // don't know what to expect, still 
> get 2
>   field.payload = foo;
> }
>
> void main() {
>   double[d2q9.d] foo;
>   auto f = Field!(double, d2q9)(foo);
>
>   f.fun();         // Sure, this works
>   // f.fun2(foo);  // Won't work without additional alias
>   f.fun3(foo);     // Works, so are we happy?
>   f.fun4(foo);     // No! This isn't supposed to work...
>   f.fun5(foo);     // Nor this...
> }
>
> Any thoughts?

I don't know if there's a reason why fun2 doesn't work. I don't 
see one.

fun4 and fun5 work correctly. They are the same as fun3, just 
with other default values for d. Those default values are not 
used, because d is inferred from the argument to be 2. If you 
pass a double[3], d is inferred to be 3 (and the compiler 
complains on `field.payload = foo`).

You can use a static assert or a template constraint to work 
around fun2 not working:

void fun6(T, size_t d)(T field, double[d] foo)
{
   static assert(d == T.conn.d);
   ...
}
void fun7(T, size_t d)(T field, double[d] foo) if(d == T.conn.d)
{
   ...
}


More information about the Digitalmars-d-learn mailing list