[英]Why always specify iterators in std::for_each?
據我所知,迭代STL集合的習慣看起來像這樣:
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 ++,雖然)。
我絕對是STL的ga-ga。 但我記不起實際上曾經使用過for_each
。
這個成語是
for ( container::iterator it = coll.begin(); it != coll.end(); ++ it )
C ++ 11引入了糖來減少這種情況
for ( auto elem : coll )
這與您的便捷函數類似,但使用免費(非成員) std::begin
和std::end
函數,這些函數允許與非標准容器的對象兼容。
另外,查一下(我還沒有玩這個,因為它還沒有在GCC中),看起來它限制了程序員訪問范圍的元素,而不是迭代器。
至於使用容器來指代其整個范圍,最好保持允許子范圍的靈活性。 另一種解決方案是為一對迭代器{ 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 )
指定開始和結束迭代器而不僅僅是集合確實很乏味且容易出錯(例如,您的示例代碼錯誤地嘗試在a
而不是v
上調用.begin()
和.end()
)。 這就是Boost Range發明的原因。 有了它,您可以編寫如下代碼:
int a[] = { 1,2,3 };
boost::for_each(a, some_function);
它還介紹了范圍適配器的概念,它可以用算法組成,以增加它們的實用性和通用性。
[推測] STL使用迭代器而不是范圍的原因是它是從構造算法的角度構思的,然后找到這些算法的最低要求並根據這些要求表達它們。 算法需要迭代器來完成它們的工作,即使算法使用的自然事物實際上是值的范圍。 正如在另一個答案中提到的那樣,STL處於嚴重的時間壓力之下,因此這些問題從未得到解決。 幸運的是,我們現代人有Boost.Range,所以我們可以使用基於范圍的算法。
你的建議沒有什么不妥,盡管我不得不說Boost.ForEach與現在的C ++世界中的東西一樣接近“慣用”。
這種方法的好處,在使用中看起來像:
BOOST_FOREACH(value_type i, collection) {
function(i);
}
是你也可以內聯你的操作,而不是嚴格限制顯式功能映射。
原因是STL的設計者來自理論方面。 在Comp.Sci中,范圍是一個比容器更基本的概念。 在實踐中,容器更為常見。 STL是在1996 - 1998年的嚴重時間壓力下加入的,並沒有積極地進行重構。
您在std::for_each
的第三個參數中看到了類似的問題。 理論上,lambda存在。 在C ++ 98中,他們沒有。 因此,您必須在線外定義仿函數,對綁定器和合成器使用詳細語法,或使用無狀態指針到函數。
就個人而言,我認為所有STL算法都應該采用一個范圍(單個對象),而不是一對迭代器。 將后者包含在一個范圍內是微不足道的。 現在你看到ostream_iterators必須定義一個相當任意的結束對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.