2011-04-11 56 views
2

據我所知,用於遍歷STL集合成語看起來是這樣的:爲什麼總是在std :: for_each中指定迭代器?

int a[] = { 1,2,3 }; 
std::vector<int> v(a, a+3); 

std::for_each(a.begin(), a.end(), some_function); 

指定第一張和最後一個迭代器,如果我想只在一定的範圍內收集的工作是有用的,或者做一些更有創意的事情,但大多數時候,我懷疑我們實際上想要與整個系列合作。所以,我不知道爲什麼人們在這種情況下打擾指定迭代器(因爲他們永遠是相同的),也不要只使用一個方便的功能沿着這些線路:

namespace easy 
{ 
    template <class T, class F> 
    F for_each(T& collection, F function) 
    { 
    std::for_each(collection.begin(), collection.end(), function); 
    return function; 
    } 
} 

(當然,這是可能的,這做事的慣用方式,我從來沒有注意到!我是新的C++,雖然)。

+1

我很想知道,大多數STL大型項目都有一個「算法助手」頭,其中包含像'for_each'這樣的函數。我常用的有一個'for_all',用於執行你的函數,以及用於指針的範圍和容器的'indirect_for_each'和'indirect_for_all'。 – 2011-04-11 03:54:45

回答

5

絕對是STL的完全ga ga。但我實在記不起使用for_each

成語是

for (container::iterator it = coll.begin(); it != coll.end(); ++ it) 

C++ 11引入糖此減少到

for (auto elem : coll) 

這類似於您的方便功能,但使用遊離(非成員)std::beginstd::end函數允許與非標準容器的對象兼容。它看起來像它限制程序員訪問範圍的元素,而不是迭代器進入它。它看起來像限制程序員訪問該範圍的元素,而不是迭代器。


至於使用容器來指代其整個範圍,最好保持允許子範圍的靈活性。替代解決方案是引入迭代器的的成語,{ begin, end }。有一些爭論,我希望C++ 11包括特徵,使得

begin(make_pair(begin_, end_)) // == begin_, 
end(make_pair(begin_, end_)) // == end_, 
for (auto elem : make_pair(begin_, end_)) // iterates over [ begin_, end) 

,但在閱讀它看起來像pair標準缺乏這種功能。

您可以創建自己的這種pair,但是,爲了獲得靈活的基於範圍for

template< typename iter > 
struct range_type { 
    iter first, last; 

    // use friends because Standard specifies these should be found by ADL: 
    friend iter begin(range_type const &r) { return r.first; } 
    friend iter end(range_type const &r) { return r.last; } 
}; 

template< typename iter > 
range_type<iter> range(iter first, iter last) 
    { return range_type<iter>{ first, last }; } 

// usage: 
for (auto elem : range(begin_, end_)) // iterates over [ begin_, end) 
+0

謝謝(特別是關於下一個C++!)。 – 2011-04-11 03:41:53

+0

@Jonathan:更新了更多這樣的細節 – Potatoswatter 2011-04-11 04:01:20

1

沒有什麼錯,你有什麼建議,但我不得不說,Boost.ForEach與當今C++領域中的「慣用」差不多。

這種方法,其在使用時看起來像的好處:

BOOST_FOREACH(value_type i, collection) { 
    function(i); 
} 

的是,你還可以內嵌運營並不能嚴格綁定到一個明確的功能映射。

1

的原因是,STL的設計者從理論方面來了。在Comp.Sci中,範圍是比容器更基本的概念。實際上,集裝箱更常見。1996年至1998年,STL在嚴重的時間壓力下加入,並沒有積極地進行重構。

您看到一個與std::for_each的第三個參數類似的問題。理論上,lambda存在。在C++ 98中,他們沒有。因此,您必須定義一個不符合函子的函數,使用帶有綁定器和合成器的冗長語法,或者使用無狀態指針函數。我個人認爲所有的STL算法都應該有一個範圍(單個對象),而不是一對迭代器。將後者包裹在一個範圍內是微不足道的。現在你看到ostream_iterators必須定義一個相當隨意的結束對象。

2

指定的開始和結束迭代器,而不是僅僅收集確實是繁瑣且容易出錯(例如你的示例代碼錯誤地試圖打電話.begin().end()a而不是v)。這就是爲什麼Boost Range被髮明的原因。有了它,你可以編寫代碼如:

int a[] = { 1,2,3 }; 
boost::for_each(a, some_function); 

它還引入了一系列的適配器,可以用算法來組成乘其實用性和通用性的概念。 [推測] STL使用迭代器代替範圍的原因在於它是從構建算法的觀點出發,然後找到這些算法的最低要求,並根據這些要求表達它們。算法需要迭代器才能完成他們的工作,即使算法使用的自然事實際上是值的範圍。正如在另一個答案中提到的,STL受到了嚴峻的時間壓力,所以這些問題從未解決。幸運的是,我們現代人有Boost.Range,所以我們可以使用基於範圍的算法。

相關問題