Перегрузка * (iterator + n) и * (n + iterator) в классе итераторов C ++?
-
19-09-2019 - |
Вопрос
(Примечание:Я пишу этот проект только для обучения;комментарии о том, что это излишне, есть...э-э, излишне.;)
Я пытаюсь реализовать итератор произвольного доступа, но я нашел очень мало литературы по этому вопросу, поэтому я использую метод проб и ошибок в сочетании со списком прототипов перегрузки операторов Wikpedias.До сих пор это работало достаточно хорошо, но я наткнулся на загвоздку.
Код, такой как
exscape::string::iterator i = string_instance.begin();
std::cout << *i << std::endl;
работает и выводит первый символ строки.Однако * (i + 1) не работает, как и *(1 + i).Моя полная реализация, очевидно, была бы немного перебором, но вот в чем суть:
namespace exscape {
class string {
friend class iterator;
...
public:
class iterator : public std::iterator<std::random_access_iterator_tag, char> {
...
char &operator*(void) {
return *p; // After some bounds checking
}
char *operator->(void) {
return p;
}
char &operator[](const int offset) {
return *(p + offset); // After some bounds checking
}
iterator &operator+=(const int offset) {
p += offset;
return *this;
}
const iterator operator+(const int offset) {
iterator out (*this);
out += offset;
return out;
}
};
};
}
int main() {
exscape::string s = "ABCDEF";
exscape::string::iterator i = s.begin();
std::cout << *(i + 2) << std::endl;
}
Вышеприведенный сбой с (строка 632 - это, конечно, строка * (i + 2)):
string.cpp:В функции ‘int main()’:строка.cpp:632:ошибка:нет совпадения для ‘operator *’ в ‘*exscape::string::iterator::operator+(int)(2)’ строка.cpp:105:примечание:кандидатами являются:символ и exscape::строка::итератор::оператор*()
*(2 + i) сбой с:
string.cpp:В функции ‘int main()’:строка.cpp:632:ошибка:нет совпадения для ‘operator+’ в ‘2 + i’ строка.cpp:434:примечание:кандидатами являются:exscape::строка exscape::оператор+(const char*, const exscape::строка&)
Я предполагаю, что мне нужно сделать еще немного перегрузки, но я не уверен, какого оператора мне не хватает.
Решение
Во-первых, вам нужен operator *(void) const
.
[Править:основываясь на вашем существующем операторе, необходимо выполнить следующее:
char &operator *(void) const {
// bounds checking
return *p;
}
]
Во-вторых, вам нужен operator+(int, exscape::string::iterator)
.Довольно распространенным способом написать это было бы (в классе iterator):
friend const iterator operator+(const int offset, iterator out) {
out += offset;
return out;
}
Обратите внимание, что пометка friend делает его функцией, не являющейся членом, даже если он определен внутри класса.Возможно, вы также захотите заменить operator+(int)
с функцией, не являющейся членом, operator+(iterator,int)
, просто для того, чтобы вы получили те же неявные правила преобразования, применяемые к LHS и RHS +.
[Еще одна правка:как вы указали в своем комментарии, operator + не должен возвращать const iterator
в любом случае - просто вернись iterator
.Итак, для вашего примера кода вам на самом деле не нужно operator*()const
.Но он у вас все равно должен быть, потому что пользователи могут захотеть написать код, используя измененные константой экземпляры вашего класса.]
Наконец, стандартные контейнеры с итераторами произвольного доступа (включая std::string) определяют подписанный difference_type
как член класса. int
может быть недостаточно большим, чтобы содержать все возможные смещения (например, в архитектуре LP64), но ptrdiff_t
это хороший кандидат.
Другие советы
Ваш +
operator возвращает итератор const, но у вас нет const operator*
.Добавьте один, и я думаю, с вами все будет в порядке.Или, как предложено xtofl ниже, вы можете создать свой operator*
константа.Это лучший дизайн, если только вам действительно не нужен неконстантный operator*
по какой-то причине.
Чтобы заставить его работать с числовой константой слева, вам понадобится функция, не являющаяся членом.Что-то вроде этого (непроверенный код):
exscape::string::iterator operator+(exscape::string::iterator it, size_t n) {
return it += n;
}
exscape::string::iterator operator+(size_t n, exscape::string::iterator it) {
return it += n;
}
Я не верю, что * (2 + i) будет работать, поскольку левый операнд должен быть вашего собственного типа.На самом деле вы говорите компилятору добавить ваш итератор к 2, что не имеет никакого смысла.(i + 2) означает переместить мой итератор вперед на два индекса.
Смотрите на C ++ Faq Lite для получения дополнительной информации.