Maybe it's a silly question, but I'm stuck on it now.
How does the following code work?
// g++ main.cpp -std=c++23
#include <iterator>
int main() {
using It = std::basic_const_iterator<int*>;
using CIt = std::basic_const_iterator<const int*>;
It it1, it2;
CIt cit;
auto d1 = it1 - it2; // ?
auto d2 = it1 - cit; // ?
}
From cppreference and GCC source, there is no operator -
for two basic_const_iterator
s. The defined operator -
s are:
basic_const_iterator::operator-( const Sentinel& s )
(cppref, source)friend operator-( const Sentinel& s, const basic_const_iterator& i )
(cppref, source)friend operator-( const basic_const_iterator& i, difference_type n )
(cppref, source)Could someone explain how it1 - it2
and it1 - cit
would work? Thanks!
As many others have commented (thanks!), it1 - it2
calls it1.operator -(it2)
, or precisely:
template< std::sized_sentinel_for<Iter> S >
constexpr difference_type operator-( const S& s ) const;
But still I wasn't satisfied because they didn't explain why. So I did a bit research myself.
Here is how it works:
(using It = basic_const_iterator<int *>
)
it1 - it2
==> it1.operator -(it2)
, because
sized_sentinel_for<It, int*>
(ref) is true, because
The missing part of the puzzle was int* == It
, until I tried the following code:
struct A {
constexpr bool operator ==(int) const { return true; }
};
int main() {
static_assert(1 == A{});
}
int == A
can be synthesized from A::operator ==(int)
in the new C++!
(Seems the feature was introduced in C++20. Could someone point me to the Standard?)
So finally:
int* == It
==> It::operator ==(int*)
, because
size_sentinel_for<int*, int*>
is true.Actually, operator <=>
has the same synthesising, but not 2nd comparisons (!=, <, >, <=, >=):
#include <compare>
struct A {
constexpr bool operator ==(int) const { return true; }
constexpr auto operator <=>(int) const { return std::strong_ordering::equal; }
};
int main() {
static_assert(1 == A{});
static_assert((1 <=> A{}) == std::strong_ordering::equal);
}