[英]Can I legally use a struct with overloaded operator() as Compare for std::upper_bound?
[英]Can I use std::upper_bound without an underlying container?
我有一系列整數[start, end]
和一個非遞減單調函數f(i)
。 所以從概念上講,我有一個非遞減序列[f(start), f(start + 1), .. , f(end)]
。 我可以使用std::upper_bound
該序列找到的第一個元素i
在保存范圍f(i) > some_value
?
從概念上講,我喜歡這樣的事情:
std::upper_bound(start, end + 1, some_value, [&](int lhs, int rhs) {
return f(lhs) < f(rhs);
});
但這不會編譯,因為start
和end + 1
不符合forward迭代器的要求。
簡短的回答是肯定的,因為std::upper_bound
適用於迭代器,而不適用於容器。 但迭代器本身是相應類的實例(例如, std::vector<int>::iterator
或whatnot)。
如果你構造一些特定的類來滿足ForwardIterator
的要求, ForwardIterator
不是實際上綁定到某種容器,雖然仍然有意義(例如,如果你想在程序上生成序列),它應該可以正常工作。
請注意,簡單整數不會起作用。 另一方面,一個類,其對象為特定參數值(帶有一些額外的電池)保存函數的值,將會。
基本上有兩個答案:
它是按照標准工作還是適用於STL的所有實際實現?
根據標准,正如TC已經指出的那樣 ,對迭代器有一些嚴格的要求,特別是*it
必須返回一個(可能是const)對value_type
引用(我們通過返回對迭代器成員的引用來滿足),但是我們還需要it1 == it2
, *it1
和*it2
是綁定到同一個對象的引用,只有當我們為該范圍內的每個數字都有一個不同的對象時才有可能。
如果你想在實踐中使用這個想法,我不相信std::upper_bound
或類似方法的任何實現實際上都依賴於這個引用相等,所以你可以只使用一個封裝整數作為迭代器的類,只重載必要的方法 。 據我boost::irange
, boost::irange
滿足了這些要求
正如您所看到的,這不是嚴格符合標准的,但我認為沒有理由為什么任何二進制搜索的實現都應該依賴迭代器的強大要求,如果底層的“存儲”仍然是const。
不,不是實際,但在實踐中是肯定的,但如果你想要實踐則不是。
upper_bound
需要ForwardIterator 。 ForwardIterator要求*
返回的實際值, 並且如果兩個迭代相等則它們指代相同的對象。
對於無容器迭代器,這需要一個非常復雜的迭代器,它將它返回的值緩存在某種共享的全局映射中。 為了使它變得一半實用,請注意迭代器要求對所述參考的壽命幾乎沒有說明; 所以你想要引用計數並銷毀所述值,因為有問題的迭代器不再存在。
這樣的解決方案需要同步,全局狀態,並且比boost::integer_range
更加昂貴和復雜。 沒有理智的人會寫這個,除非作為演示標准需要修復的練習。
沒有合理的upper_bound
實現實際上要求所討論的迭代器是完整的前向迭代器,除非進行完整的概念檢查以驗證標准(而不是實際算法需要的)。 輸入迭代器在返回的值上具有穩定性,幾乎可以肯定。 在C ++標准中沒有這樣的概念,並且前向迭代器是標准中最弱的迭代器類別,它滿足它。
這個問題,有效地要求迭代器由容器支持,在我看來是標准的一個缺陷。 無容器迭代器功能強大且有用,除非它們在技術上很少在標准容器中工作。
添加新的迭代器類別已經證明是有問題的,因為在不破壞現有代碼的情況下幾乎沒有辦法。 他們調查它是為了連續的迭代器,並把它寫下來是不切實際的(我不知道他們嘗試過的所有細節)。
添加沒有標記支持的新迭代器概念是更有可能的,但可能必須等到概念是C ++語言的一部分而不僅僅是標准; 然后嘗試添加新概念成為您可以在C ++而不是標准中指定的東西,這使得它更容易。
但是,這會導致程序格式錯誤,無需診斷。 所以考慮是否值得; 實際上,重新實現upper_bound
比維護每個執行都是未定義行為的程序更容易,並且每次編譯都受編譯器升級的支配。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.