Перегрузка * (iterator + n) и * (n + iterator) в классе итераторов C ++?

StackOverflow https://stackoverflow.com/questions/1709478

Вопрос

(Примечание:Я пишу этот проект только для обучения;комментарии о том, что это излишне, есть...э-э, излишне.;)

Я пытаюсь реализовать итератор произвольного доступа, но я нашел очень мало литературы по этому вопросу, поэтому я использую метод проб и ошибок в сочетании со списком прототипов перегрузки операторов 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 для получения дополнительной информации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top