我可以想到幾個選擇,每個選項都有自己的醜陋。
一個顯而易見的選擇是使用指針(可能unique_ptr
),而不是引用。當然,爲了這個工作,它要麼需要從堆中分配,要麼需要自定義分配器。我認爲用一個好的分配器,這種方法有一些優點。然後再次,操作員超載會變得討厭。
另一種方法是按值而不是通過const引用存儲子表達式。這種方法的效率非常依賴編譯器,但由於你基本上處理了一堆臨時對象,所以我想現代編譯器可以優化副本(或者至少是很多副本)。
最後一種方法可以讓你相同的結構保持你的代碼,但強制用戶來計算表達式。它要求你只有一個迭代類型,它是表達式的基本類型(比如說,std::vector<int>
)。沒有任何一個表達類應該爲它們定義方法或函數,但應該只能轉換爲基礎類型begin
和end
。這樣,代碼for(auto x : expr)
將在編譯時失敗(因爲expr
不可迭代),但編寫for(auto x : static_cast<vector<int>>(expr))
的工作原理是因爲表達式已經過計算。
如果您希望使用基於範圍的for循環來實現表達式模板操作,那麼您可以在表達式模板類中提供專用或受保護的begin
和end
方法。只要確保每個模板類都可以訪問其他模板類的begin
和end
方法。在這種情況下應該沒問題,因爲表達式模板是函數的一個參數,所以在函數中編寫循環時,您不必擔心懸掛引用。
的'汽車&&'在基於範圍的'for'循環可能真的變成是東西砸自己的腳很容易 - 我還沒有真正理解到底是什麼影響的範圍類型,爲什麼(左值引用非常量:危險的,非引用:unproblematic,???)。 – Philipp 2012-03-05 23:24:52
@菲利普:沒有「範圍類型」這樣的東西。只有符合範圍「概念」的類型。具體來說,有一對'begin/end'覆蓋返回輸入迭代器。 – 2012-03-07 03:16:51
我想答案是確保表達式模板不符合範圍「概念」,即他們沒有「開始」和「結束」。 – Clinton 2012-03-07 06:35:43