Возможно, это глупый вопрос, но я сейчас застрял на нем.
Как работает следующий код?
// 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; // ?
}
Из cppreference и источника GCC нет operator -
для двух basic_const_iterator
. Определенные operator -
:
basic_const_iterator::operator-( const Sentinel& s )
(cppref , источник)friend operator-( const Sentinel& s, const basic_const_iterator& i )
(cppref , источник)friend operator-( const basic_const_iterator& i, difference_type n )
(cppref , источник)Может ли кто-нибудь объяснить, как будут работать it1 - it2
и it1 - cit
? Спасибо!
Что это такое? en.cppreference.com/w/cpp/iterator/basic_const_iterator/… Он просто вызывает auto d1 = it1.operator-(it2);
.
Может ли кто-нибудь объяснить, как будет работать
it1 - it2
?
Это эквивалентно написанию it1.operator-(it2)
, в котором используется перегруженный оператор - версия 1.
Обратите внимание, что выбранная перегрузка является функцией-членом, как видно из опущенного спецификатора друга в объявлении operator-
в стандарте C++.
template< std::sized_sentinel_for<Iter> S > constexpr difference_type operator-( const S& s ) const; (1) (since C++23)
Когда мы применим это к it1.operator-(it2)
, одним из возможных экземпляров будет:
long std::basic_const_iterator<int*>::operator-<std::basic_const_iterator<int*> >(std::basic_const_iterator<int*> const&) const;
Вот Iter = std::basic_const_iterator<int*>
,
и difference_type = long
Спасибо! Не могли бы вы объяснить, почему выбран именно этот вариант? Точнее, как It
удовлетворяет sized_sentinel_for<Iter>
?
@DoZerg Обратите внимание, что Iter
в std::sized_sentinel_for<Iter> S
— это параметр шаблона класса Iter
.
Как многие другие прокомментировали (спасибо!), it1 - it2
звонит it1.operator -(it2)
, а точнее:
template< std::sized_sentinel_for<Iter> S >
constexpr difference_type operator-( const S& s ) const;
Но все же я не был удовлетворен, потому что они не объяснили почему. Поэтому я провел небольшое исследование самостоятельно.
Вот как это работает:
(using It = basic_const_iterator<int *>
)
it1 - it2
==> it1.operator -(it2)
, потому что
sized_sentinel_for<It, int*>
(ссылка) верно, потому что
It == int*
==> It::operator ==(int*)
(ссылка), потому что
size_sentinel_for<int*, int*>
это правда.int* == It
действует (почему?)It - int*
==> It::operator -(int*)
, потому что
sized_sentinel_for<int*, int*>
это правда.int* - It
==> operator -(int*, It)
(ссылка), потому что
sized_sentinel_for<int*, int*>
это правда.Недостающей частью головоломки была int* == It
, пока я не попробовал следующий код:
struct A {
constexpr bool operator ==(int) const { return true; }
};
int main() {
static_assert(1 == A{});
}
int == A
можно синтезировать из A::operator ==(int)
в новом C++!
(Кажется, эта функция появилась в C++20. Может ли кто-нибудь указать мне на стандарт?)
Итак, наконец:
int* == It
==> It::operator ==(int*)
, потому что
size_sentinel_for<int*, int*>
это правда.Собственно, operator <=>
имеет тот же синтез, но не 2-е сравнения (!=, <, >, <=, >=):
#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);
}
В it1 - it2
S
— это basic_const_iterator<int*>
, а не int*
. it1 - it2
звонит it1.current_ - it2
который звонит it1.current_ - it2.current_
.
@Барри S
— это It
, что есть basic_const_iterator<int*>
в моем ответе выше.
Разве
basic_const_iterator
не удовлетворяетbasic_const_iterator::operator-( const Sentinel& s )
?