Search code examples
c++c++20range-v3std-ranges

Why std::ranges::view_interface using CRTP


According to cppreference, the helper class template for defining views view_interface using the curiously recurring template pattern (CRTP) techniques.

What is the design philosophy behind them? Is there a dramatic advantage versus overriding a virtual base class method in the derived class?


Solution

  • If you give a base class virtual functions, then it has those functions. Always. It can never not have those functions, and every class derived from it will inherit those functions.

    view_interface has an empty function if and only if the range category for the type is forward_range. That is, empty exists if begin returns a forward iterator, and end returns a sentinel for that iterator. But you can only test that if you can query properties of the derived class. And the base class can't do that... unless you allow it to by giving it the derived class type. Which means it has to be a template parameter, and the base class is a template.

    And therefore, you're using CRTP.

    Providing common functions or not based on the iterator categories of the derived range class is the entire point of the class. The only alternative is to have a bunch of base classes for each iterator type. So you'd have forward_view_interface for forward ranges, contiguous_view_interface for contiguous ranges, etc. And that'd be painful. But it would start to experience multiplicative explosion, because some properties provided by view_interface are orthogonal to the iterator category.

    For example size is provided if the range is a sized range. But that may happen for any iterator category, even input iterators. So you now need sized_forward_view_interface, etc.

    Or you can just use the CRTP.