Question

(Note: I'm writing this project for learning only; comments about it being redundant are... uh, redundant. ;)

I'm trying to implement a random access iterator, but I've found very little literature on the subject, so I'm going by trial and error combined with Wikpedias list of operator overload prototypes. It's worked well enough so far, but I've hit a snag.

Code such as

exscape::string::iterator i = string_instance.begin();
std::cout << *i << std::endl;

works, and prints the first character of the string. However, *(i + 1) doesn't work, and neither does *(1 + i). My full implementation would obviously be a bit too much, but here's the gist of it:

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;
}

The above fails with (line 632 is, of course, the *(i + 2) line):

string.cpp: In function ‘int main()’: string.cpp:632: error: no match for ‘operator*’ in ‘*exscape::string::iterator::operator+(int)(2)’ string.cpp:105: note: candidates are: char& exscape::string::iterator::operator*()

*(2 + i) fails with:

string.cpp: In function ‘int main()’: string.cpp:632: error: no match for ‘operator+’ in ‘2 + i’ string.cpp:434: note: candidates are: exscape::string exscape::operator+(const char*, const exscape::string&)

My guess is that I need to do some more overloading, but I'm not sure what operator I'm missing.

Was it helpful?

Solution

First, you need an operator *(void) const.

[Edit: based on your existing operator, the following should do:

char &operator *(void) const {
    // bounds checking
    return *p;
}

]

Second, you need an operator+(int, exscape::string::iterator). A fairly common way to write this would be (in the iterator class):

friend const iterator operator+(const int offset, iterator out) {
    out += offset;
    return out;
}

Note that marking it friend makes it a non-member function, even though it is defined inside the class. You might also want to replace the operator+(int) with a non-member function, operator+(iterator,int), just so that you get the same implicit conversion rules applied to the LHS and RHS of the +.

[Another edit: as you point out in your comment, operator+ shouldn't be returning const iterator anyway - just return iterator. So for your code example, you don't actually need operator*()const. But you should have one anyway, because users might want to write code using const-modified instances of your class.]

Finally, standard containers with random access iterators (including std::string) define a signed difference_type as a member of the class. int might not be big enough to contain all possible offsets (for example on an LP64 architecture), but ptrdiff_t is a good candidate.

OTHER TIPS

Your + operator returns a const iterator, but you don't have a const operator*. Add one, and I think you'll be all right. Or, as suggested by xtofl below, you can make your operator* const. That's better design, unless you really need the non-const operator* for some reason.

To have it work with the numeric constant on the left you will need a non-member function. Something like this (untested code):

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;
}

I don't believe *(2 + i) will work since the left hand operand needs to be your own type. You're actually telling the compiler to add your iterator to 2, which makes no sense. (i + 2) means move my iterator forward two indexes.

See the C++ Faq Lite for more information.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top