簡體   English   中英

為什么總是在std :: for_each中指定迭代器?

[英]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::beginstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM