2012-01-15 19 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

對於靜態數組,因爲它們不是有效的前向範圍,所以isForwardRangefalse。他們必須有有效的front,emptypopFront

範圍必須在迭代時發生變異。 popFront刪除範圍中的第一個元素,將範圍的長度減1。靜態數組不能被突變。他們的元素可以,但他們不能。

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

是非法的。因此,popFront無法使用靜態數組,因此靜態數組不能使用範圍。

frontempty,並且popFront被宣佈爲std.array陣列和frontempty將與靜態數組工作,因爲他們明確地採取動態數組(沒有範圍),以及靜態數組可以隱式轉換爲動態數組當一個函數需要一個動態數組(一個靜態數組的切片)。但是,popFront將不起作用,因爲它需要一個動態數組的ref。而且,我指出,無論popFront的實現如何,popFront都不能與靜態數組一起工作,因爲不能像範圍所需的那樣改變靜態數組。

現在至fill,它需要一個前向範圍,而不是一個數組。因此,IFTI(隱式函數模板實例化)將嘗試使用靜態數組類型(不是動態數組類型)。而且由於isForwardRange對於靜態數組是false,所以fill無法使用靜態數組進行編譯。但是,當您切片靜態數組時,您然後傳遞動態數組,其中isForwardRangetrue。所以,它的工作。並且因爲切片指向相同的元素,並且fill變異了元素而不是數組,所以靜態數組中的元素被fill變異。

但是,要謹慎地將靜態數組的切片傳遞給函數。只要靜態數組存在,就沒有問題。但是一旦靜態數組離開作用域,它的任何一部分都是無效的。所以,做類似

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

會很糟糕。對a的引用正在轉義foo--即其最後3個元素的一部分。

因此,如果您將靜態數組的切片傳遞給函數,則需要確保沒有對該數組的引用進行轉義。然而,fill應該沒問題。

+0

我是說你必須用'Array'和'SList'來切片?似乎有點設計缺陷。 – 2012-01-16 22:01:34

+0

這不是一個真正的設計缺陷恕我直言。更多的情況是動態數組是奇怪的範圍特例。但是,由於它們是目前最常見的情況,因此我們習慣於這樣做。容器必須隱式轉換爲其IFTI的片類型,以便在傳遞給函數時不需要顯式切片,並且將使得將容器傳遞給模板化函數更加困難。而且我不確定所有切片類型都會被IFTI自動切片是一個好主意 - 即使在處理範圍時也是如此。 – 2012-01-16 23:02:51

+0

你可以這樣想。容器 - 包括靜態數組 - 需要被切片以獲得範圍。所以,如果你想要任何理由的範圍 - 包括傳遞到基於範圍的函數 - 你必須明確地切片。但動態數組是_already_範圍而不是容器,所以切片是不必要的。 – 2012-01-16 23:05:36

7

isForwardRange檢查爲front的存在,empty性能和popfront()功能

的問題是,popfront()需要收縮數組,你(應該)知道你不能調整大小的靜態數組但一個靜態數組(本質上是一個正常的動態數組)的片可以調整(這當然不影響靜態數組)

澄清a.popfront()需要從int[4]變換到int[3]但那是不可能的

+0

即popfront的參數和返回類型必須相同? – BCS 2012-01-18 19:32:17

+0

'popfront'是一個改變'this'參數的函數,所以'front'屬性改變(指向'next'元素)(也許是'empty'屬性),這對靜態數組是不可能的,因爲長度是在編譯時和部分類型中設置的。 – 2012-01-18 19:47:01