2012-01-15 2 views
10

Это работает:является статическим массивом переднего диапазона?

int[] a = [ 1, 2, 3, 4 ]; 
fill(a, 5); 

, но это не делает:

int[4] a = [ 1, 2, 3, 4 ]; 
fill(a, 5); 

и я получаю эту ошибку:

Error: template std.algorithm.fill(Range,Value) if (isForwardRange!(Range) && is(typeof(range.front = filler))) does not match any function template declaration

вместо этого, я должен это сделать для того, чтобы работа со статическими массивами:

int[4] a = [ 1, 2, 3, 4 ]; 
fill(a[], 5); 

Может кто-нибудь объяснить это поведение, пожалуйста?

ответ

7

isForwardRange - false для статических массивов, поскольку они недопустимы для дальности вперед. Они должны иметь действительные front, empty и popFront.

Диапазон должен быть мутированным по мере его повторения. popFront удаляет первый элемент из диапазона, уменьшая длину диапазона на единицу. статические массивы не могут быть мутированы. Их элементов может быть, но их не может быть.

int[5] a; 
a.length = 4; 

является незаконным. Таким образом, popFront не может работать со статическими массивами, поэтому статические массивы не могут быть диапазонами.

front, empty и popFront объявлены для массивов в std.array и front и empty будет работать со статическими массивами, так как они явно принимают динамические массивы (не диапазоны), и статические массивы могут быть неявно преобразованы в динамические массивы когда функция принимает динамический массив (берется срез статического массива). Однако popFront не будет работать, поскольку для динамического массива требуется ref. И, как я указал, popFront не может быть выполнен для работы со статическими массивами независимо от реализации popFront, поскольку вы не можете мутировать статический массив, как это требуется для диапазона.

Теперь, как для fill, он принимает дальний диапазон, а не массив. Таким образом, IFTI (имплицирование неявных функций) будет пытаться использовать с ним тип статического массива (а не тип динамического массива). А так как isForwardRange является false для статического массива, fill не может скомпилироваться со статическим массивом. Однако, когда вы разрезаете статический массив, вы затем передаете динамический массив, для которого isForwardRangeistrue. Таким образом, он работает.И поскольку срез указывает на те же элементы и fill мутирует элементы, а не массив, элементы в статическом массиве мутируются на fill.

Будьте осторожны, однако, передавая кусочки статических массивов в функции. Пока существует статический массив, все в порядке. Но как только статический массив покинет область видимости, любой ее фрагмент окажется недействительным. Итак, что-то вроде

int[] foo() 
{ 
    int[5] a = [1, 2, 3, 4, 5] 
    return find(a[], 3); 
} 

было бы очень плохо. Ссылка на a ускользает от foo - а именно среза его последних 3 элементов.

Итак, если вы передаете срез статического массива функции, вы должны быть уверены, что ссылки на этот массив не исчезают. fill, однако, должно быть хорошо.

+0

Правильно ли я говорю, что вам нужно обрезать «Array» и «SList»? Похоже, что это недостаток дизайна. –

+0

Это не дизайн дефекта ИМХО. Это скорее случай, когда динамические массивы представляют собой странный частный случай диапазонов. Но так как в настоящее время это самый распространенный случай, это то, к чему мы привыкли. Контейнеру нужно было бы неявно преобразовать его в свой тип среза для IFTI, чтобы он не нуждался в явном разрезе при передаче функции, и что было бы намного сложнее передать контейнеры в шаблонные функции. И я не уверен, что было бы хорошей идеей, чтобы все разрезанные типы были автоматически разрезаны с помощью IFTI в целом - даже при работе с диапазонами. –

+0

Вы можете думать об этом так. Контейнеры, включая статические массивы, должны быть нарезаны, чтобы получить диапазон над ними. Таким образом, если вы хотите, чтобы диапазон по ним по какой-либо причине - включая переход к функции на основе диапазона, - вы должны явно нарезать их. Но динамические массивы - это уже _ диапазоны, а не контейнеры, поэтому нарезка не нужна. –

7

isForwardRange проверяет существование front, empty свойства и popfront() функции

вопрос в том, что popfront() потребуется сжать массив, как вы (должны) знаете, что вы не можете изменить размер статического массива, но кусочек статического массива (по существу, обычный динамический массив) может быть изменен (это, конечно, не влияет на статический массив)

уточнить a.popfront() будет необходимо преобразование из int[4] в int[3], но это не возможно

+0

Т.е. аргументы и возвращаемые типы popfront должны быть одинаковыми? – BCS

+0

'popfront' - это функция, которая изменяет параметр' this', поэтому свойство 'front' изменяется (указывая на« следующий »элемент) (и, возможно, свойство' empty'), это невозможно для статического массива, потому что длина устанавливается во время компиляции и часть типа. –

Смежные вопросы