From skimming through named requirements and iterator concepts on cppreference.com, I infer that prior to C++20, things like InputIterator
(now LegacyInputIterator
), ForwardIterator
(now LegacyForwardIterator
) only existed as named requirements (as defined in the standard) and not baked in in the language. The burden to ensure that a type T
satisfies a requirement R
lies with the iterator writer/algorithm user. Also, I imagine, you can’t write a trait(type metafunction), for something like a, RandomAccessIterator
which must support constant-time ++
and +=
operations.
So, pre- C++20 iterator concepts aren’t actually concepts in the sense of the C++20 language feature.
With C++20, these requirements have been formalized as C++ concepts. The older STL algorithm variants have been left untouched. For instance, if you look at std::find
, an implementation would have the interface:
template< class InputIt, class T >
( InputIt first, InputIt last, const T& value ); InputIt find
So, it doesn’t use concepts to constrain InputIt
. The user of the legacy algorithms has to vouch for the passed types to satisfy the legacy requirements stated in the standard, otherwise the call will cause undefined behavior.
But, the newer ranges algorithms, for example, ranges::find
constrain the arguments to satisfy various predicates.
template< std::input_iterator I, ...>,
constexpr I find(I first,...)