2011-04-11 62 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,所以我们可以使用基于范围的算法。

相关问题