Article by Ayman Alheraki on April 4 2026 04:18 PM
std::for_each vs. Range‑based for LoopBoth std::for_each (from <algorithm>) and the range‑based for loop (C++11 and later) iterate over every element of a container. However, they have different strengths, syntax, and ideal use cases. Since your article covers <functional>, std::for_each is especially relevant because it shines when you already have a callable object (like a functor from <functional>) that you want to apply.
Range‑based for | std::for_each |
|---|---|
for (int c : values) { doSomething(c); } | std::for_each(values.begin(), values.end(), doSomething); |
| Clean, built‑in language feature. | Algorithm from <algorithm>. Works with any iterator pair. |
Use range‑based for when… | Use std::for_each when… |
|---|---|
| You need a simple, readable loop for most cases. | You already have a named function/functor (e.g., std::function, std::mem_fn, std::plus). |
You want to break early (break;) or skip (continue;). | You want to compose operations with std::bind or use parallel execution (C++17). |
You need to modify the loop variable inside (e.g., for (auto& x : vec)). | You’re writing generic code that should work with any iterator pair (not just containers). |
| Performance is critical and you want zero overhead (compilers optimise both equally well). | You want to combine with other algorithms (e.g., std::transform, std::accumulate) in a functional pipeline. |
| Feature | Range‑based for | std::for_each |
|---|---|---|
| Readability | Excellent for simple iteration. | Slightly more verbose, but expressive when using named functions. |
| Early exit | break, continue, return (inside function) | No – must throw exception or use std::find_if etc. |
| Iterator flexibility | Works only on containers with begin()/end(). | Works on any iterator pair (e.g., raw array, stream iterators). |
| Parallel execution (C++17) | Not available. | Yes: std::for_each(std::execution::par, …) |
| Return value | None (statement, not expression). | Returns the function object (useful for state). |
Use with std::function | You can call a std::function inside the body. | Directly accepts any callable, including std::function. |
| Performance | Identical (both are zero‑overhead abstractions). | Identical (both inline to same machine code). |
std::vector<int> values = {1, 2, 3, 4, 5};
// Range‑based forfor (int x : values) { std::cout << x << ' ';}
// std::for_eachstd::for_each(values.begin(), values.end(), [](int x) { std::cout << x << ' '; });
<functional>void increment(int& n) { ++n; }
// Range‑based forfor (int& x : values) { increment(x);}
// std::for_each – cleaner when you already have the functionstd::for_each(values.begin(), values.end(), increment);
std::mem_fn with std::for_eachstruct Person { void greet() const; };std::vector<Person> people;
// Range‑based forfor (const auto& p : people) { p.greet();}
// std::for_each – very concisestd::for_each(people.begin(), people.end(), std::mem_fn(&Person::greet));
// Range‑based for cannot be parallelised directly.// std::for_each can:std::for_each(std::execution::par, values.begin(), values.end(), [](int& x) { x *= 2; });
std::for_each returns the callable after processing. This is useful for accumulating state.
struct Sum { int total = 0; void operator()(int x) { total += x; }};
Sum s = std::for_each(values.begin(), values.end(), Sum());std::cout << "Sum = " << s.total << '\n';
With a range‑based for, you would need an external accumulator variable:
int total = 0;for (int x : values) total += x;// total holds the sum
Both work, but std::for_each encapsulates the state inside the functor.
Both constructs compile to identical assembly for simple operations. There is no performance penalty for using std::for_each – it’s just a template that inlines the loop. The range‑based for is also syntactic sugar for a traditional iterator loop.
Example compiled with -O2 (both produce the same loop):
// Range‑based forfor (int x : values) sum += x;
// std::for_eachstd::for_each(values.begin(), values.end(), [&](int x){ sum += x; });
Prefer range‑based for for most day‑to‑day loops – it’s simpler, supports break, and is very readable.
Use std::for_each when:
You already have a callable object (e.g., from <functional>) and want to apply it directly.
You need parallel execution.
You are writing generic code that works with arbitrary iterator pairs.
You want to use the return value (stateful functor).
You are working in a “functional” style (pipeline of algorithms).
<functional>std::for_each is a natural partner for <functional> because it directly accepts:
std::function objects,
results of std::bind,
std::mem_fn wrappers,
built‑in functors like std::plus, std::greater (though those are unary/binary, so you’d need std::bind or a lambda to adapt them).
Example:
std::vector<int> v = {1,2,3};std::for_each(v.begin(), v.end(), std::bind(std::multiplies<int>(), std::placeholders::_1, 2));// multiplies each element by 2
But in modern C++, a lambda is often clearer than std::bind. Still, std::for_each remains a valid choice.
Final verdict: Both are excellent tools. Know both and choose the one that makes your code most expressive and maintainable. For teaching <functional>, std::for_each provides a perfect stage to demonstrate callable objects.