10

In §25.2.4.2 of the C++ standard (std::for_each):

template<class InputIterator, class Function> Function for_each(InputIterator first, InputIterator last, Function f); 

Effects: Applies f to the result of dereferencing every iterator in the range [first,last), starting from first and proceeding to last - 1.

  • Does this mean that f is applied to the elements of a container in order?
  • If so, does the parallel mode of libstdc++ violate it?
  • If not, why is the range-based for loop in §6.5.4 not implemented as a call to std::for_each? (this would allow range-based for loops to also be automatically parallelized by the implementation)

2 Answers 2

8
  • Does this mean that f is applied to the elements of a container in order?

I originally said no, but I think it does mean that, yes. Other algorithms don't include that specific wording.

  • If so, does the parallel mode of libstdc++ violate it?

Maybe, the parallel mode is an extension, and somewhat experimental, not really claiming to be a 100% conforming implementation of the standard library. (If it does claim that somewhere in the docs I'll fix the docs! ;-)

  • If not, why is the range-based for loop in §6.5.4 not implemented as a call to std::for_each? (this would allow range-based for loops to also be automatically parallelized)

Range-based for does not depend on the standard library to work. If std::begin and std::end are visible they might be used, but are not required. Also, it would involve packaging up the loop body as a lambda so you have a function object to pass to std::for_each, which would complicate the specification of range-based for, which is supposed to have the same semantics and be exactly as efficient as a hand-written for loop. But the real reason might be that noone thought to do it that way!

Sign up to request clarification or add additional context in comments.

5 Comments

Some of us were having a similar discussion about std::generate which led to this question. I suspect you may be in a position to shed some light on this :-)
I'm afraid I have no particular insight about sequential guarantees ... it's something I keep meaning to look into
I've always written std::for_each because I thought it was more ''parallelization friendly'' than a for-loop (just replace it with a lib::parallel_for_each, or maybe just compile with openMP and let the compiler choose a parallel implementation of it for you). This is keeping me from switching to the more confortable range-based for loops. I thought that maybe they would be implemented as just a call to std::for_each, sad to hear they aren't :(
Another difference is when aborting mid-sequence: for_each can only do so by throwing an exception, while range-based for can also do so with a break or return statement.
@Nevin I personally don't like throwing an exception inside for each, the algorithm literally means for each element in the range. Throwing an exception changes its meaning to for each element in the range, or not. If you want to break, just let the lambda return for the remaining elements if a condition is met. That way you still traverse the sequence till the end. This maps good to the concept of parallel for eachs: OpenMP (and others) doesn't allow you to break out of loops either.
3

If not, why is the range-based for loop in §6.5.4 not implemented as a call to std::for_each? (this would allow range-based for loops to also be automatically parallelized)

Well, std::for_each is not allowed by the standard to be "automatically parallelized" (it must proceed sequentially, as stated in the standard), so there's that. But more importantly, range-based for allows other things besides std::for_each. As a language feature, you get to, for example, break out of the loop. You can use goto or other language constructs. And so forth.

std::for_each is based around calling a function for each iteration. And you can't really "break" out of a function.

3 Comments

Thanks! Yes you can break out of a range-based for. Does this mean that std::for_each should still be preferred if you think about future parallelization? You can't break out of a parallel openmp loop so actually std::for_each maps better with openmp than the range-based for.
@gnzlbg: No. std::for_each is not allowed to be parallelized. There are algorithms like it that can be, but std::for_each isn't for that. If you're doing a loop that you want to be done in parallel, you should use an appropriate algorithm for that. std::for_each is not that algorithm.
thanks! After reading the answers now I know that std::for_each is not allowed to be parallelized. However, I was asking now if in the case I might be thinking of parallelizing a loop in the future, should I still prefer std::for_each over range-based for loops because its requirements map better with those of parallel loops? Changing std::for_each to my::parallel_for_each should be easier than moving away from a range-based for loop.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.