Date
2022-09-05.00:00:00
Message id
12752

Content

Currently, basic_const_iterator::operator== is defined as a friend function:

template<sentinel_for<Iterator> S>
  friend constexpr bool operator==(const basic_const_iterator& x, const S& s);

which only requires S to model sentinel_for<Iterator>, and since basic_const_iterator has a conversion constructor that accepts I, this will result in infinite constraint checks when comparing basic_const_iterator<int*> with int* (online example):

#include <iterator>

template<std::input_iterator I>
struct basic_const_iterator {
  basic_const_iterator() = default;
  basic_const_iterator(I);
  template<std::sentinel_for<I> S>
  friend bool operator==(const basic_const_iterator&, const S&);
};
  
static_assert(std::sentinel_for<basic_const_iterator<int*>, int*>); // infinite meta-recursion

That is, sentinel_for ends with weakly-equality-comparable-with and instantiates operator==, which in turn rechecks sentinel_for and instantiates the same operator==, making the circle closed.

The proposed resolution is to change operator== to be a member function so that S is no longer accidentally instantiated as basic_const_iterator. The same goes for basic_const_iterator::operator-.