9

I am writing a thin template wrapper for iterators, and hit a stumbling block when passing through the structure dereference operator, mainly because pointers don't have one:

#include <vector>

struct mystruct {
    int member;
};

template<class iterator>
struct wrap {
   typedef typename std::iterator_traits<iterator>::pointer pointer;
   iterator internal;
   pointer operator->() {return internal.operator->();} //MARK1
};

int main() {
    wrap<std::vector<mystruct>::iterator> a;
    a->member;
    wrap<mystruct*> b;
    b->member;
    return 0;
}

http://ideone.com/XdvEz

prog.cpp: In member function ‘typename std::iterator_traits<_Iter>::pointer wrap<iterator>::operator->() [with iterator = mystruct*]’:
prog.cpp:18:   instantiated from here
prog.cpp:11: error: request for member ‘operator->’ in ‘((wrap<mystruct*>*)this)->wrap<mystruct*>::internal’, which is of non-class type ‘mystruct*’

This following method works, but I don't think it's guaranteed to work. Namely, if an iterator has a strange pointer type that isn't the same as a pointer to a value_type.

   pointer operator->() {return &*internal;} //MARK3
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • 1
    What version of C++ has a *structure dereference operator*? – Thomas Matthews Dec 16 '11 at 19:14
  • Why `char*`? Wouldn't there be some sort of `Iterator::value_type` somewhere? – Kerrek SB Dec 16 '11 at 19:25
  • 3
    @ThomasMatthews: That's what [wikipedia](http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Member_and_pointer_operators) calls it. The C++ standard just calls it `operator->`. – Mooing Duck Dec 16 '11 at 19:25
  • I don't understand what you want to return - a reference to the object, or the iterator, or a pointer to the object? Yes, don't write pseudo-code, but *minimal, representative code*. – Kerrek SB Dec 16 '11 at 19:28
  • Wouldn't template specialization be the right way to do it? – lapk Dec 16 '11 at 19:30
  • @KerrekSB: Replaced `char` with `mystruct` that has a member. Question should make sense now. I didn't realize it didn't make sense, because IDEone was giving me the expected error message. – Mooing Duck Dec 16 '11 at 19:33
  • @AzzA: If template specialization is required, that's an option, but I feel like there should be a way to do this. – Mooing Duck Dec 16 '11 at 19:42
  • @Thomas Matthews I'm glad I discovered the term _structure dereference operator_ since '->' is impossible to Google for :P. – Daniel Buckmaster Jan 01 '12 at 18:01
  • @AzzA: As it turns out, I went with specialization, since I needed a homogeneous return type. – Mooing Duck Jan 09 '12 at 18:13

1 Answers1

10

The standard indirectly says that an overloaded operator-> has to either return a pointer, an object that is convertible to a pointer, or an object that has overloaded operator->. Your best bet is to just return internal.

§13.5.6 [over.ref] p1

An expression x->m is interpreted as (x.operator->())->m

(The above applies recursively.)

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • And before you ask about `operator*()`, return type is `iterator_traits::reference` and return just `*iterator`. Any iterator that does not return a `reference` on dereference doesn't model the iterator concept correctly and can be savely ignored. – Xeo Dec 16 '11 at 20:03
  • Yeah, I got `operator*`, but it never dawned on me to return a `iterator` instead of a `pointer`. Thanks! I expect this is the answer but I'll try to give it a day or so for other suggestions. – Mooing Duck Dec 16 '11 at 20:20
  • 1
    I would just add, that the recursion ends when a pointer is returned (or an object convertible to a pointer), so if operator-> returns a pointer you've hit the recursion base case and you're done. If operator-> returns something else with an operator-> overload, then you recurse. This may seem obvious, but it took me a while to sort it out. – Pete Baughman Sep 17 '13 at 00:28