digitalmars.D.learn - Strange alias behaviour in template arguments
- Stefan Frijters (73/73) Mar 03 2015 So this is a strange thing I ran into while trying to streamline
- anonymous (19/93) Mar 03 2015 I don't know if there's a reason why fun2 doesn't work. I don't
- Stefan Frijters (4/109) Mar 03 2015 Ah, yes, I was misinterpreting the alias. fun7() would work for
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?
Mar 03 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) { ... }
Mar 03 2015
On Tuesday, 3 March 2015 at 14:40:45 UTC, anonymous wrote:On Tuesday, 3 March 2015 at 13:42:09 UTC, Stefan Frijters wrote:Ah, yes, I was misinterpreting the alias. fun7() would work for me, although it's a shame fun2() doesn't... Cheers.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) { ... }
Mar 03 2015