2009-04-17 5 views
24

При использовании алгоритма std :: for_each, как я могу сломаться при выполнении определенного условия?Ломать в std :: for_each loop

+0

Мне лично не нравится выходить из-за цикла. IMO, цикл должен использоваться только тогда, когда вам нужно полностью повторить. Если вы хотите перерыть между собой, рассмотрите другие конструкции цикла. – 2009-04-17 13:23:26

+4

Попробуйте: std :: find_if –

ответ

10

Вы можете использовать алгоритм find_if, который остановит и вернет итератор, где условие предиката, применяемое к итерированному элементу, вернет true. Поэтому ваш предикат должен быть изменен, чтобы возвращать логическое значение как условие продолжения/прерывания.

Однако это взломать, поэтому вы можете использовать алгоритмы.

Другой способ - использовать BOOST_FOREACH.

+0

Да, я могу это сделать, но что, если я хочу применить некоторые операции к элементам цикла, пока условие не будет выполнено? – Naveen

+0

Naveen, что с этим? вы можете выполнять любую операцию над элементами. то в любое время вы можете «сломать»; и петля выходит. –

+0

find_if принимает итераторы ввода, а не выводит итераторы. Тогда я бы рекомендовал реализовать цикл вручную или использовать BOOST_FOREACH. –

2

Вы не можете этого сделать, если не выбрали исключение, что не является хорошей идеей, поскольку вы не контролируете поток с помощью исключений.

Обновление: очевидно, у Boost есть for_each_if, что может help, но вы не используете Boost.

+0

вам не нужен boost для использования for_each_if(). Его просто реализовать. –

+0

Правильно, но вопрос не в том, «как мне реализовать for_each_if()». –

+0

for_each_if тоже не решает вопрос. Это было не «как заставить мой код ничего не делать по элементам после определенного момента», а «как полностью остановить итерацию». Могут быть некоторые серьезные затраты на производительность для прохождения всего диапазона, если итерация могла быть прервана раньше. Таким образом, ответ - это исключения или ничего. (где ничего не означает «редизайн», поэтому вам не нужно ломаться или не использовать for_each для этого ».) – jalf

13

Вы можете выйти из функции for_each(), выбросив исключение из своего функтора. Однако это часто не очень хорошая идея, и есть альтернативы.

Вы можете сохранить состояние в своем функторе. Если вы обнаруживаете условие «break», просто установите флаг в свой функтор, а затем для каждой последующей итерации просто вернитесь, не выполняя действия вашего функтора. Очевидно, это не остановит итерацию, которая может быть дорогой для больших коллекций, но она, по крайней мере, остановит работу.

Если ваша коллекция отсортирована, вы можете найти() элемент, который хотите разбить, а затем сделать for_each от begin() до возвращаемого элемента().

Наконец, вы можете реализовать for_each_if(). Это снова не остановит итерацию, но не будет оценивать ваш функтор, который выполняет работу, если предикат оценивает значение false. Вот 2 варианта for_each_xxx(), который принимает значение и выполняет работу, если оператор ==() оценивается как true, а другой - два функтора; который выполняет сравнение ala find_if(), а другой, который выполняет работу, если оператор сравнения оценивает значение true.

/* --- 

    For each 
    25.1.1 

     template< class InputIterator, class Function, class T> 
      Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f) 

     template< class InputIterator, class Function, class Predicate > 
      Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f) 

    Requires: 

     T is of type EqualityComparable (20.1.1) 

    Effects:  

     Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold: 

      1: *i == value 
      2: pred(*i) != false 

    Returns:  

     f 

    Complexity: 

     At most last - first applications of f 

    --- */ 

    template< class InputIterator, class Function, class Predicate > 
    Function for_each_if(InputIterator first, 
         InputIterator last, 
         Predicate pred, 
         Function f) 
    { 
     for(; first != last; ++first) 
     { 
      if(pred(*first)) 
       f(*first); 
     } 
     return f; 
    }; 

    template< class InputIterator, class Function, class T> 
    Function for_each_equal(InputIterator first, 
          InputIterator last, 
          const T& value, 
          Function f) 
    { 
     for(; first != last; ++first) 
     { 
      if(*first == value) 
       f(*first); 
     } 
     return f; 
    }; 
+0

Вы можете сломать, выбросив исключение. Но решение find() лучше в некоторых случаях не менее – jalf

+0

True; отредактированный ответ для включения другого ввода. –

+0

Я рассмотрел этот ответ после того, как просто прочитал код, но должен сказать, что исключение только для того, чтобы разорвать цикл раньше, никогда не является хорошей идеей, если вам действительно не нужно бросать, если условие выполняется. –

0

Вы делаете исключение. Независимо от того, является ли это хорошей идеей, это вопрос типа стиля, темп @Dan, но может быть больше проблем с вашим дизайном. for_each предназначен для своего рода функционально-программирующего стиля, который подразумевает, что ваша функция может применяться равномерно по множеству. Итак, если вам do необходимо сломать, это может быть непринужденным необычным условием и, следовательно, достойным исключения.

Другое решение и более «функциональное» решение состоит в том, чтобы написать вашу функцию, чтобы она не влияла на некоторые приложения, а затем записывала ее, чтобы она не влияла. Так, например, если у вас была функция суммирования, добавьте ее 0 в случаях, из которых вы «сломали».

+3

Отбрасывание исключений для управления потоком - это не вопрос стиля. Это вопрос вкуса. Плохой вкус, то есть. –

+1

Похоже, что это вопрос слепого фанатизма больше, чем вкус. Это делает работу, проще, чище и элегантнее, чем большинство других решений. Я согласен с Чарли в этом. Если вы * должны * сломаться от for_each, то 1) вероятно, будет основная проблема дизайна, и 2) бросание исключения - это самое простое решение. Пока исключение может быть настолько чисто изолировано (это одна строка кода, которую нужно обернуть в try/catch), использование этого для управления потоком допустимо. – jalf

+0

Это похоже на старую фанатическую фанатику. Да, gotos могут быть вредными, но иногда на некоторых языках они являются лучшими из доступных вариантов. –

6

Если вы хотите сделать некоторые действия, пока условие не выполняется, возможно, вам нужно изменить алгоритм на что-то вроде ?

+2

Это простой способ. Просто верните истину, когда вы хотите остановиться. –

4

Как уже было показано другими, это возможно только с обходными решениями, которые ИМХО запутывает код.

Итак, мои предложения - изменить for_each на обычный цикл. Это сделает его более заметным для других, что вы используете break (и, возможно, даже продолжаете).

20

Вы можете использовать std :: any_of (или std :: all_of или std :: none_of), например. как это:

std::vector<int> a; 
// ...  
std::all_of(a.begin(), a.end(), [&](int val) { 
    // return false if you want to break, true otherwise 
    }); 

Однако это расточительно решение (возвращаемые значения на самом деле не используется ни для чего), и вы лучше писать у вас есть цикл.

+2

Лучший ответ, который действительно помог – York

+0

Отличный ответ ... – Ash

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