Annex D (informative) Compatibility [diff]

D.1 C++ and Ranges [diff.cpp]

This section details the known breaking changes likely to effect user code when being ported to the version of the Standard Library described in this document.

D.1.1 Algorithm Return Types [diff.cpp.algo_return]

The algorithms described in this document permit the type of the end sentinel to differ from the type of the begin iterator. This is so that the algorithms can operate on ranges for which the physical end position is not yet known.

The physical end position of the input range is determined during the execution of many of the algorithms. Rather than lose that potentially useful information, the design presented here has such algorithms return the iterator position of the end of the range. In many cases, this is a breaking change. Some algorithms that return iterators in today's STL are changed to return pairs, and algorithms that return pairs today are changed to return tuples. This is likely to be the most noticeable breaking change.

Alternate designs that were less impactful were considered and dismissed. See Section 3.3.6 in N4128 (niebler2014) for a discussion of the issues.

D.1.2 Stronger Constraints [diff.cpp.constraints]

In this proposal, many algorithms and utilities get stricter type checking. For example, algorithms constrained with LessThanComparable today are constrained by StrictTotallyOrdered in this document. This concept requires types to provide all the relational operators, not just operator<.

The use of coarser-grained, higher-level concepts in algorithm constraints is to make the type checks more semantic in nature and less syntactic. It also has the benefit of being less verbose while giving algorithm implementors greater implementation freedom. This approach is in contrast to the previous effort to add concepts to the Standard Library in the C++0x timeframe, which saw a proliferation of small, purely syntactic concepts and algorithm constraints that merely restated the algorithms' implementation details more verbosely in the algorithms' function signatures.

The potential for breakage must be carefully weighed against the integrity and complexity of the constraints system. The coarseness of the concepts may need to change in response to real-world usage.

D.1.3 Constrained Functional Objects [diff.cpp.functional]

The algorithm design described in this document assumes that the function objects std::equal_to and std::less get constraints added to their function call operators. (The former is constrained with EqualityComparable and the latter with StrictTotallyOrdered). Similar constraints are added to the other function objects in <functional>. As with the coarsely-grained algorithm constraints, these function object constraints are likely to cause user code to break.

Real-world experience is needed to assess the seriousness of the breakage. From a correctness point of view, the constraints are logical and valuable, but it's possible that for the sake of compatibility we provide both constrained and unconstrained functional objects.

D.1.4 Iterators and Default-Constructibility [diff.cpp.defaultconstruct]

In today's STL, iterators need not be default-constructible. The Iterator concept described in this document requires default-constructibility. This could potentially cause breakage in users' code. Also, it makes the implementation of some types of iterators more complicated. Any iterator that has members that are not default constructible (e.g., an iterator that contains a lambda that has captured by reference) must take special steps to provide default-constructibility (e.g., by wrapping non-default-constructible types in something like std::optional, as specified in the C++17 Working Draft N4618 §20.6). This can weaken class invariants.

The guarantee of default-constructibility simplifies the implementation of much iterator- and range-based code that would otherwise need to wrap iterators in std::optional. But the needs of backward-compatibility, the extra complexity to iterator implementors, and the weakened invariants may prove to be too great a burden.

We may in fact go even farther and remove the requirement of default-constructibility from the Semiregular concept. Time and experience will give us guidance here.

D.1.5 iterator_traits cannot be specialized [diff.cpp.iteratortraits]

In this STL design, iterator_traits changes from being a class template to being an alias template. This is to intentionally break any code that tries to specialize it. In its place are the three class templates difference_type, value_type, and iterator_category. The need for this traits balkanization is because the associated types belong to separate concepts: difference_type belongs to WeaklyIncrementable; value_type belongs to Readable; and iterator_category belongs to InputIterator.

This breakage is intentional and inherent in the decomposition of the iterator concepts established by the Palo Alto report (palo-alto).