简体   繁体   English

打破std :: for_each循环

[英]Breaking in std::for_each loop

使用std :: for_each算法时如何在满足某个条件时中断?

You can use std::any_of (or std::all_of or std::none_of) eg like this: 你可以使用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
  });

However, this is a wasteful solution (return values are not really used for anything), and you're better off writing you own loop. 但是,这是一个浪费的解决方案(返回值并没有真正用于任何事情),你最好写自己的循环。

You can break from the for_each() by throwing an exception from your functor. 您可以通过从仿函数中抛出异常来中断for_each()。 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. 如果你检测到'break'条件,只需在你的仿函数中设置一个标志,然后对于每个后续的迭代,只需返回而不做你的仿函数的事情。 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. 如果您的集合已经排序,您可以找到()要中断的元素,然后从begin()到返回的元素find()执行for_each。

Finally, you can implement a for_each_if() . 最后,您可以实现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. 这将再次不会停止迭代,但是如果谓词的计算结果为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; 这里有2种for_each_xxx() ,一种取值,如果operator ==()计算结果为true,另一种取两个仿函数; one which performs a comparison ala find_if(), and the other which performs the work if the comparison operator evaluates to 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;
    };

You can use find_if algorithm, which will stop and return the iterator where the predicate condition applied to the iterated element returns true. 您可以使用find_if算法,它将停止并返回迭代元素,其中应用于迭代元素的谓词条件返回true。 So your predicate should be changed to return a boolean as the continue/break condition. 因此,应该更改谓词以返回布尔值作为continue / break条件。

However, this is a hack, so you can use the algorithms. 但是,这是一个黑客,所以你可以使用算法。

Another way is to use BOOST_FOREACH. 另一种方法是使用BOOST_FOREACH。

如果你想在条件不满足的情况下做一些动作,也许你需要改变像std::find_if这样的算法?

As already shown by others it is only achievable with workarounds that IMHO obfuscate the code. 正如其他人已经表明的那样,只有通过IMHO模糊代码的变通方法才能实现。

So my suggestions is to change the for_each into a regular for loop. 所以我的建议是将for_each更改为常规for循环。 This will make it more visible to others that you are using break (and maybe even continue). 这将使其他人更容易看到你正在使用break(甚至可能继续)。

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. 更新:显然Boost有一个可能有帮助的for_each_if,但你没有使用Boost。

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. 无论这是一个好主意是一种风格问题,节奏@Dan,但可能更多的是你的设计问题。 for_each is intended for a sort of functional-programming style, which implicitly assumes that your function can be applied uniformly across the set. for_each用于某种函数式编程风格,它隐含地假设您的函数可以在整个集合中统一应用。 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。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM