Better C++ Ranges

Speaker: Arno Schödl

Audience level: [ Intermediate | Advanced ]

Ranges have been in the C++ standard for while now, and find their way into modern codebases. At think-cell, we have been developing and using our own range library for 20 years, which is built on top of the standard and is compatible with it, but goes beyond it in many aspects. Range adaptors are often stacked, a filter on top of a transform on top of etc. To make such a stack efficient, iterators are not good enough. We use a new concept that is more efficient and at the same time compatible with iterators so library users can keep using iterators as they did before. The standard library is very strict about the distinction between containers and views, and range adaptors are views which must maintain a reference to the data being adapted. Instead, we allow range adaptors to hold data themselves to make them self-contained and lazily evaluated at the same time. The standard iterator model only allows external iteration. However, internal iteration is often much easier to implement than external iteration. For many applications, internal iteration is completely adequate and more efficient than external iteration. Therefore, we bring internal iteration into the range family, to the point that the library user may not know or care which kind of iteration is being used. Standard algorithms return iterations and use the end iterator to signal some singleton state. By customizing return values, we can make our code more terse and expressive, for example eliminating these dreaded iterator end checks. These features combined make ranges an excellent tool for text formatting. We can use these ranges to represent the values to be formatted, conceptually turning them into lazily evaluated strings. These can be used just like regular strings are used today: in function returns; as standard algorithm input; embedded into other, equally lazily evaluated strings; and so on, before they are finally expanded for display. By choosing the right interfaces, we can optimize this expansion at compile-time, allowing both nice syntax and a performance which is very close to manually optimized code.