In this recipe, we iterated over files, and for every file, we checked its status and size. While all our per-file operations are fairly straightforward and simple, our actual directory traversal looked a bit magic.
In order to traverse our directory, we just instantiated a directory_iterator and then iterated over it. Traversing a directory is fantastically simple with the filesystem library.
for (const directory_entry &e : directory_iterator{dir}) {
// do something
}
There is not much more to say about this class apart from the following things:
- It visits every element of the directory once
- The order in which the directory elements are iterated is unspecified
- Directory elements . and .. are already filtered out
However, it might be noticeable that directory_iterator seems to be an iterator, and an iterable range at the same time. Why? In the minimal for loop example we just had a look at, it was used as an iterable range. In the actual recipe code, we used it like an iterator:
transform(directory_iterator{dir}, {},
back_inserter(items), file_info);
The truth is, it is just an iterator class type, but the std::begin and std::end functions provide overloads for this type. This way we can call the begin and end function on this kind of iterator and they return us iterators again. That might look strange at first sight, but it makes this class more useful.