问题
This works:
int[] a = [ 1, 2, 3, 4 ];
fill(a, 5);
but this doesn't:
int[4] a = [ 1, 2, 3, 4 ];
fill(a, 5);
and I get this error:
Error: template std.algorithm.fill(Range,Value) if (isForwardRange!(Range) && is(typeof(range.front = filler))) does not match any function template declaration
instead, I have to do this in order for it to work with static arrays:
int[4] a = [ 1, 2, 3, 4 ];
fill(a[], 5);
could any one explain this behavior please?
回答1:
No. isForwardRange
is false
for static arrays, because they're not valid forward ranges. They must have a valid front
, empty
, and popFront
.
A range must be mutated as it's iterated over. popFront
removes the first element from the range, reducing the length of the range by one. static arrays cannot be mutated. Their elements can be, but they can't be.
int[5] a;
a.length = 4;
is illegal. So, popFront
cannot work with static arrays and therefore static arrays cannot be ranges.
front
, empty
, and popFront
are declared for arrays in std.array, and front
and empty
will work with static arrays, because they explicitly take dynamic arrays (not ranges), and static arrays can be implicitly converted to dynamic arrays when a function takes a dynamic array (a slice of the static array is taken). However, popFront
won't work, because it requires a ref
of a dynamic array. And as, I pointed out, popFront
can't be made to work with static arrays regardless of popFront
's implementation, because you can't mutate a static array as would be required for a range.
Now as for fill
, it takes a forward range, not an array. So, IFTI (implicit function template instantiation) will try and use the static array type (not the dynamic array type) with it. And since isForwardRange
is false
for a static array, fill
fails to compile with a static array. However, when you slice the static array, you're then passing a dynamic array, for which isForwardRange
is true
. So, it works. And because, the slice points to the same elements, and fill
mutates the elements and not the array, the elements in the static array are mutated by fill
.
Be wary, however, of passing slices of static arrays to functions. As long as the static array exists, it's fine. But once the static array leaves scope, any slice of it is then invalid. So, doing something like
int[] foo()
{
int[5] a = [1, 2, 3, 4, 5]
return find(a[], 3);
}
would be very bad. A reference to a
is escaping foo
- namely a slice of its last 3 elements.
So, if you are passing a slice of a static array to a function, you need to be sure that no references to that array escape. fill
, however, should be fine.
回答2:
isForwardRange
checks for the existence of the front
, empty
properties and popfront()
function
the issue is that popfront()
would need to shrink the array, as you (should) know you can't resize a static array but a slice of a static array (essentially a normal dynamic array) can be resized (this of course doesn't affect the static array)
to clarify a.popfront()
would need to transform a from int[4]
to int[3]
but that's not possible
来源:https://stackoverflow.com/questions/8873265/is-a-static-array-a-forward-range