is a static array a forward range?

偶尔善良 提交于 2019-12-23 07:49:05

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!