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)
{
...
}