在C ++ 0X中使用基于范围的for循环,我知道我们能够做到:
std::vector<int> numbers = generateNumbers();
for( int k : numbers )
{
processNumber( k );
}
(用lambda编写可能更简单)
但如果我只想将processNumber(k)应用于数字的一部分,我该怎么办?例如,我应该如何编写for for循环以将processNumber()应用于数字的一半(头部或尾部)?像Python或Ruby一样允许“切片”吗?
答案 0 :(得分:13)
您可以使用sliced库中的“range adaptor”Boost.Range:
#include <boost/range/adaptor/sliced.hpp>
using boost::adaptors::sliced;
...
std::vector<int> numbers = generateNumbers();
for( int k : numbers | sliced(0, numbers.size() / 2))
{
processNumber( k );
}
答案 1 :(得分:3)
一种可能性可能是提升iterator_range
(没有一个支持基于范围的编译器,而是使用BOOST_FOREACH
。我希望基于范围的工作相同,只要容器或范围有开始和结束方法。)
#include <boost/foreach.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
BOOST_FOREACH(int n, boost::make_iterator_range(v.begin(), v.begin() + v.size() / 2)) {
std::cout << n << '\n';
}
}
为方便起见,您也可以创建自己的切片函数,因此它会接受索引而不是迭代器。同样,它可以基于boost.iterator_range,或者不是:
#include <cstddef>
#include <iterator>
template <class Iterator>
class iter_pair
{
public:
typedef Iterator iterator;
typedef Iterator const_iterator; //BOOST_FOREACH appears to want this
iter_pair(iterator first, iterator last): first(first), last(last) {}
iterator begin() const { return first; }
iterator end() const { return last; }
private:
iterator first, last;
};
template <class Container>
struct iterator_type
{
typedef typename Container::iterator type;
};
template <class Container>
struct iterator_type<const Container>
{
typedef typename Container::const_iterator type;
};
template <class Container>
iter_pair<typename iterator_type<Container>::type>
slice(Container& c, size_t i_first, size_t i_last)
{
typedef typename iterator_type<Container>::type iterator;
iterator first = c.begin();
std::advance(first, i_first);
iterator last = first;
std::advance(last, i_last - i_first);
return iter_pair<iterator>(first, last);
}
template <class Container>
iter_pair<typename iterator_type<Container>::type>
slice(Container& c, size_t i_last)
{
return slice(c, 0, i_last);
}
//could probably also be overloaded for arrays
#include <cctype>
#include <string>
#include <boost/foreach.hpp>
#include <iostream>
int main()
{
std::string s("Hello world, la-la-la!");
BOOST_FOREACH( char& c, slice(s, 2, 11)) {
if (c == 'l')
c = std::toupper(c);
}
const std::string& r = s;
BOOST_FOREACH( char c, slice(r, r.size() - 1) ) {
std::cout << c << " ";
}
std::cout << '\n';
}
通常一个人可能会首先使用迭代器,所以它可能没那么有用。
答案 2 :(得分:0)
这样的东西可能有用(未经检查,因为我无法访问C ++ 0x编译器),
编辑:在VS10上查看过,当然我必须修复错误的错误....
定义一个类,它是任何容器的代理,其iterator
只返回容器的子集。我提供的示例是给出前半部分的最简单的例子,但它可以更加通用。
template <class Container>
class head_t {
Container& c_;
public:
template <class T>
class iter {
T curr_;
const T& end_;
int limit_; // count how many items iterated
public:
iter(T curr, const T& end)
: curr_(curr)
, end_(end)
, limit_(std::distance(curr_, end_)/2)
{ }
typename Container::value_type operator*() { return *curr_; }
// Do the equivilant for for operator++(int)
iter& operator++() {
if (--limit_ == 0) // finished our slice
curr_ = end_;
else
++curr_;
return *this;
}
bool operator!=(const iter& i) const {
return curr_ != i.curr_;
}
};
head_t(Container& c) : c_(c) {}
iter<typename Container::iterator> begin() {
return iter<typename Container::iterator>(c_.begin(), c_.end());
}
iter<typename Container::iterator> end() {
return iter<typename Container::iterator>(c_.end(), c_.end());
}
};
template <class T>
head_t<T> head(T& t) { return head_t<T>(t); }
然后你在循环中使用它:
for( int k : head(numbers) )