问题
I am writing some vector functions which operate on static D arrays like so:
real[N] unit(uint N)(real[N] v) {
real[N] u = (v[] / norm(v)); //explicit type necessary to force slice-operator
return u; //to return static-length array
}
real[3] v = unit!(3)([1,2,3]); //works
real[3] w = unit([1,2,3]); //error, compiler doesn't infer the template parameter
real[3] x = [1,2,3];
auto i = unit(x); //also works, forces statically allocated array
So, my question is, is there a way to get the compiler to infer the template parameter N if I pass a literal array directly to the function? I tried using "1.0L" format, in the hopes that the array was being cast from a static array of int or float, but that didn't work either. TL;DR Can I make the middle example (w) above work? Thanks!
Edit: Just to clarify, I've tried a few variations with specialized template parameters, but I'm not sure I've done that correctly. I have also tried, in the call, new real[3]([1,2,3])
to force a heap allocated static array (a three horned unicorn?) but I couldn't get that to compile.
回答1:
The problem is that [1,2,3]
is not a static array. It's a dynamic array, so it can't match. It's the wrong type, and there's no way to have a static array literal. If you want to pass an array literal as a static array, you're going to need to either assign it to a variable first or cast it to the type that you want.
auto w = unit(cast(real[3])[1,2,3]);
should work. Personally, I'd argue that it's best to just explicitly instantiate the template
auto w = unit!3([1, 2, 3]);
because it avoids the risk of screwing up the cast.
Now, I think that there's a definite argument that the compiler should just work in this case, but it tends to be much pickier with templates than with normal functions, since it generally instantiates templates with the exact type that you pass it without trying to do any implicit conversions, whereas a normal function would implicitly convert the dynamic array to a static one. Feel free to open an enhancement request. The behavior might get changed. It was recently changed so that IFTI (implicit function template instantiation) instantiates with the tail-const version of an array (e.g. immutable(char)[]
instead of immutable(char[])
), which has been a definite improvement. Now, that's a bit different than attempting a conversion (I believe that the compiler just automatically, always treats arrays as tail-const for IFTI), so I don't know that the odds of getting the compiler's behavior changed in this case are very high. But it doesn't hurt to ask.
回答2:
Idea/hack:
real[T.length] unit(T...)(T t)
{
real[T.length] v,u;
foreach(i,x; t) v[i] = x;
u[] = (v[] / norm(v));
return u;
}
void main()
{
real[3] v = unit(1,2,3);
}
Might not be as fast as using real[3] v = unit!3([1,2,3])
because of the foreach there, though, I suppose. Also the args gets converted to real at runtime. Hm.
来源:https://stackoverflow.com/questions/9575582/template-argument-inference-in-d