Breaking in std::for_each loop

前端 未结 7 1360
南方客
南方客 2021-01-01 10:37

While using std::for_each algorithm how do I break when a certain condition is satisfied?

相关标签:
7条回答
  • 2021-01-01 11:06

    You can break from the for_each() by throwing an exception from your functor. This is often not a good idea however, and there are alternatives.

    You can retain state in your functor. If you detect the 'break' condition, simply set a flag in your functor and then for each subsequent iteration simply return without doing your functor's thing. Obviously this won't stop the iteration, which might be expensive for large collections, but it will at least stop the work from being performed.

    If your collection is sorted, you can find() the element that you want to break at, then do for_each from begin() to the element find() returned.

    Finally, you can implement a for_each_if(). This will again not stop the iteration but will not evaluate your functor which does the work if the predicate evaluates to false. Here are 2 flavors of for_each_xxx(), one which takes a value and performs the work if operator==() evaluates to true, and another which takes two functors; one which performs a comparison ala find_if(), and the other which performs the work if the comparison operator evaluates to 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 讨论(0)
  • 2021-01-01 11:09

    As already shown by others it is only achievable with workarounds that IMHO obfuscate the code.

    So my suggestions is to change the for_each into a regular for loop. This will make it more visible to others that you are using break (and maybe even continue).

    0 讨论(0)
  • 2021-01-01 11:13

    You can't do it, unless you throw an exception, which is not a good idea because you don't do flow control with exceptions.

    Update: apparently Boost has a for_each_if that might help, but you're not using Boost.

    0 讨论(0)
  • 2021-01-01 11:14

    You throw an exception. Whether or not it's a good idea is sort of a style question, pace @Dan, but may be more of an issue with your design. for_each is intended for a sort of functional-programming style, which implicitly assumes that your function can be applied uniformly across the set. So, if you do need to break, that could be consiered an unusual condition, and therefore worthy of an exception.

    The other solution, and a more "functional" solution, is to write your function so that if it shouldn't have an effect on some applications, then write it to have no effect. So, for example, if you had a summing function, have it add 0 in the cases you would have "broken" from.

    0 讨论(0)
  • 2021-01-01 11:16

    You can use std::any_of (or std::all_of or std::none_of) e.g. like this:

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

    However, this is a wasteful solution (return values are not really used for anything), and you're better off writing you own loop.

    0 讨论(0)
  • 2021-01-01 11:23

    If you want do some actions while condition is not satisfied, maybe you need change algorithm on something like std::find_if?

    0 讨论(0)
提交回复
热议问题