Как нарезать с помощью петли для диапазона? C ++ 0x - PullRequest
8 голосов
/ 04 февраля 2010

Используя диапазон, основанный на циклах в C ++ 0X, я знаю, что мы сможем сделать:

std::vector<int> numbers = generateNumbers();

for( int k : numbers )
{
   processNumber( k );
}

(может быть, еще проще написать с помощью лямбды)

Но как мне быть, если я хочу применить processNumber (k) к части чисел? Например, как мне написать этот цикл for для применения processNumber () к половине (голове или хвосту) чисел? Разрешается ли "нарезка" как в Python или Ruby?

Ответы [ 3 ]

13 голосов
/ 29 мая 2011

Вы можете использовать " нарезанный " адаптер диапазона из библиотеки 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 );
}   
3 голосов
/ 06 февраля 2010

Одной из возможностей может быть повышение 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';
}

Как правило, сначала можно было бы работать с итераторами, так что это может быть не очень полезно.

0 голосов
/ 04 февраля 2010

Нечто подобное может работать (не проверено, поскольку у меня нет доступа к компилятору 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) )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...