14.4. Iterable Types¶
How can we visit each element in a container without depending on the container's storage details? For example, an array stores elements contiguously, while a list stores elements in separate nodes. Both can still be visited in order.
14.4.1. Positional indexing¶
An indexed loop works when the container provides positional access through
operator[]. An array is one example:
1#include <array>
2#include <cstddef>
3#include <iostream>
4#include <string>
5
6int main() {
7 const std::array<std::string, 3> names = {"Alice", "Bob", "Clara"};
8
9 for (std::size_t i = 0; i < names.size(); ++i) {
10 std::cout << names[i] << '\n';
11 }
12}
The loop above depends on two operations: size() and operator[].
std::list does not provide positional access through either operator[]
or at(). A loop that assumes an integer position therefore cannot be
adapted to a list by changing only the container type.
std::set also has no positional indexing. std::map is different:
it provides operator[] for lookup by key, not for locating an element by
position. For example, records[42] asks for the value associated with key
42; it does not mean the forty-third element.
14.4.2. Range-based for loops¶
The range-based for loop avoids explicit indexing.
The same loop syntax works for standard containers with begin() and
end(), including both arrays and lists:
1#include <array>
2#include <iostream>
3#include <list>
4#include <string>
5
6int main() {
7 const std::array<std::string, 3> names = {"Alice", "Bob", "Clara"};
8 const std::list<int> ages = {27, 3, 1};
9
10 std::cout << "names:";
11 for (const auto& name : names) {
12 std::cout << ' ' << name;
13 }
14 std::cout << '\n';
15
16 std::cout << "ages:";
17 for (const auto& age : ages) {
18 std::cout << ' ' << age;
19 }
20 std::cout << '\n';
21}
The declaration const auto& binds a reference to each existing element,
so the loop does not copy the element. The const prevents the loop body
from changing the container's elements. Use auto& when modification is
intended, or auto when an independent copy is useful.
The range-based loop hides the iterator syntax, but it still relies on the same operations: obtain a beginning position, compare it with the end position, dereference the current position, and advance to the next one. We say that containers supporting this interface are iterable.
More to Explore
Iterator Library at cppreference.com