Подтвердить что ты не робот

Разрыв в std:: for_each

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Вы можете использовать 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
  });

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

Ответ 3

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

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

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

Наконец, вы можете реализовать for_each_if(). Это снова не остановит итерацию, но не будет оценивать ваш функтор, который выполняет работу, если предикат оценивает значение false. Вот два варианта 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;
    };

Ответ 4

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

Ответ 5

Как уже было показано другими, возможно только с обходными решениями, что IMHO запутывает код.

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

Ответ 6

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

Обновление: возможно, у Boost есть файл for_each_if, который может помочь, но вы не используете Boost.

Ответ 7

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

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