2015-08-11 2 views
5

У меня есть std::vector<std::string> v; (инициализировано). Как я могу использовать цикл range-for для доступа ко всем элементам, кроме первого (по индексу нуля). Для всех элементов:C++ 11: Вектор цикла с вектором второго элемента?

for (const string & s: v) 
    process(s); 

Вместо v выражениедиапазона может быть использовано. Как Могу ли я написать выражение диапазона , чтобы пропустить первый элемент (или пропустить первые n элементов) ?

Я знаю, как получить эффект, используя v.begin() + 1 и используя классический цикл. Я ищу новую, более читаемую, рекомендованную альтернативу для этого. Возможно, что-то похожее на нарезку Python? ... как:

for s in v[1:]: 
    process(s) 
+0

Один из способов сделать новый вектор с необходимыми элементами, а затем перебрать. Или вы можете использовать 'std :: for_each': http://en.cppreference.com/w/cpp/algorithm/for_each – CinCout

+3

Вы не можете. Цикл на основе диапазона не является решением для каждой проблемы. Просто используйте обычный цикл. –

+0

Как уже упоминалось @GargAnkit, вы можете создать новый вектор с требуемыми элементами. Вы можете сделать это как часть объявления цикла с помощью векторного конструктора. Итак 'for (auto && i: std :: vector (v.begin() + 1, v.end()))'. Демо [здесь] (http://ideone.com/G9yfjx). Не такой аккуратный, как пример python, который вы показали. – Ralara

ответ

5

Создать оболочку, для которой начать() и end() возвращают правильные итераторы, а затем вы можете использовать это как второй аргумент.

#include <iostream> 
#include <vector> 

template< typename Collection > 
class FromNth 
{ 
    Collection& coll_; 
    size_t offset_; 

public: 
    FromNth(Collection& coll, size_t offset) 
     : coll_(coll), offset_(offset) 
    { 
    } 

    // will nicely resolve to const_iterator if necessary 
    auto begin() const -> decltype(coll_.begin()) 
     { return coll_.begin() + offset_; } 

    auto end() const -> decltype(coll_.end()) 
     { return coll_.end(); } 
}; 

template< typename Collection > 
FromNth<Collection> makeFromNth(Collection& collection, size_t offset) 
{ 
    return FromNth<Collection>(collection, offset); 
} 

template< typename Collection > 
auto begin(const FromNth<Collection> & wrapper) -> decltype(wrapper.begin()) 
{ 
    return wrapper.begin(); 
} 

template< typename Collection > 
auto end(const FromNth<Collection> & wrapper) -> decltype(wrapper.end()) 
{ 
    return wrapper.end(); 
} 

int main() 
{ 
    std::vector<int> coll { 2, 3, 5, 7, 11, 13, 17, 19, 23 }; 

    for(auto x : makeFromNth(coll, 1)) 
    { 
     std::cout << x << '\n'; 
    } 
    return 0; 
} 

Обратите внимание, что мой fromNth «начать» не определено поведение, если размер входных данных меньше, чем смещение. (Если он равен, то он хорошо определен и начинается == end). Поэтому сначала выполните проверку размера.

Примечание: если вы используете достаточно новую версию повышения, то iterator_range может уже предоставить вам такую ​​«коллекцию», которая похожа на мою «FromNth».

for(auto const& s : boost::make_iterator_range(v.begin() + 1, v.end())) 
{ 
    process(s); 
} 

Примечание: Приведенный выше код работает на CodingGround с помощью C++ 11 GNU 4.8.3. (Этот сайт очень медленный, хотя). Из C++ 14 вам не понадобятся инструкции -> decltype (которые необходимы в C++ 11 для шаблонов).

Выход:

sh-4.3$ g++ -std=c++11 -o main *.cpp 
sh-4.3$ main 
3 
5 
7 
11 
13 
17 
19 
23 
+0

Спасибо за информацию! Я ожидал, что уже есть какой-то std-код (и я не смог найти);) – pepr

5

Пока диапазоны не превратить его в стандартную библиотеку, вы не получите лучше, чем ваниль цикл в обычной C++:

for(auto i = begin(v) + 1, e = end(v); i !=e; ++i) 
    // Do something with *i 
+0

не так ли? См. Мой ответ. – CashCow

+1

@CashCow как вопрос о сгибании диапазона для формы, я предполагаю простой C++. Я видел достаточно Boost, чтобы знать, что * ничего * невозможно, если вы набросаете на него достаточное количество шаблонов;) – Quentin

+0

boost's iterator_range решает это красиво. Mine - это немного похоже на способ сделать iterator_range, но с нумерованного смещения, как запросил пользователь. Конечно, я могу легко переписать iterator_range. Пользователь спрашивает, можно ли это сделать на C++ 11, и я показываю, как (а не просто говорящий boost) – CashCow

Смежные вопросы