2012-03-01 62 views
9

這是我的理解表達式模板將在基於範圍的基礎上在C + + 11中斷,因爲for (auto x : expr)有一個隱含的auto&& __range = expr,這將導致懸空引用。表達式模板和基於範圍的在C + + 11

有沒有一種方法創建表達式模板類,以便他們要麼基於不等的行爲正確,或至少是拋出一個編譯錯誤?

基本上,我想,以防止表達式模板可以正確編譯,但在運行時失敗,由於懸掛引用的可能性。如果用戶忘記包裝表達式模板,只要沒有無聲的運行時錯誤,我不介意在基於範圍的應用中使用它們之前必須包裝表達式模板。

+1

的'汽車&&'在基於範圍的'for'循環可能真的變成是東西砸自己的腳很容易 - 我還沒有真正理解到底是什麼影響的範圍類型,爲什麼(左值引用非常量:危險的,非引用:unproblematic,???)。 – Philipp 2012-03-05 23:24:52

+1

@菲利普:沒有「範圍類型」這樣的東西。只有符合範圍「概念」的類型。具體來說,有一對'begin/end'覆蓋返回輸入迭代器。 – 2012-03-07 03:16:51

+1

我想答案是確保表達式模板不符合範圍「概念」,即他們沒有「開始」和「結束」。 – Clinton 2012-03-07 06:35:43

回答

2

我可以想到幾個選擇,每個選項都有自己的醜陋。

一個顯而易見的選擇是使用指針(可能unique_ptr),而不是引用。當然,爲了這個工作,它要麼需要從堆中分配,要麼需要自定義分配器。我認爲用一個好的分配器,這種方法有一些優點。然後再次,操作員超載會變得討厭。

另一種方法是按值而不是通過const引用存儲子表達式。這種方法的效率非常依賴編譯器,但由於你基本上處理了一堆臨時對象,所以我想現代編譯器可以優化副本(或者至少是很多副本)。

最後一種方法可以讓你相同的結構保持你的代碼,但強制用戶來計算表達式。它要求你只有一個迭代類型,它是表達式的基本類型(比如說,std::vector<int>)。沒有任何一個表達類應該爲它們定義方法或函數,但應該只能轉換爲基礎類型beginend。這樣,代碼for(auto x : expr)將在編譯時失敗(因爲expr不可迭代),但編寫for(auto x : static_cast<vector<int>>(expr))的工作原理是因爲表達式已經過計算。

如果您希望使用基於範圍的for循環來實現表達式模板操作,那麼您可以在表達式模板類中提供專用或受保護的beginend方法。只要確保每個模板類都可以訪問其他模板類的beginend方法。在這種情況下應該沒問題,因爲表達式模板是函數的一個參數,所以在函數中編寫循環時,您不必擔心懸掛引用。

6

對此,您通常無能爲力。如果給出表達式作爲範圍,則它必須解析爲在for語句的初始化後有效的內容。並且在編譯時沒有辦法檢測到由auto推導出的任何特定類型。

這將是更好地使你的表達系統更加舉動爲基礎,所以它沒有持有引用。這將產生更安全的結果auto比試圖存儲引用可能死了的東西。如果複製不可移動類型會給您帶來麻煩,那麼您只需要忍受它。

+2

這並不能解決問題。您的基於範圍的for循環包含隱含的'auto && __ range = listOfInt;',如果'listOfInt'實際上是某個表達式模板類的值,則可能會導致問題。 – 2012-03-02 06:35:06

+0

@RichardSmith:的確如此,我認爲在這種情況下,唯一能做的就是引入一個明確的演員或一個新的自動變量。 – Philipp 2012-03-07 21:53:07