Reputation: 3034
Some (relevant?) Background:
I have a class that provides iterator-like functionality in c++. It is used to decompress a large dataset. Behind the scenes, I have a CompressedData
object. The iterator class iterates over the compressed data and returns uncompressed Data
objects
Data ExpandingIterator::operator*() const;
The dereference operator returns a Data and not a Data& because there is no storage anywhere for an uncompressed Data object to persist. For example, the compressed data could contain the following three entries:
Then when you iterated over this collection with the ExpandingIterator, you would get:
3, 3, 3, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0
The 3s and 1s and 0s never all exist somewhere in an array at the same time. They're expanded one-at-a-time from the compressed data. Now, the real data is more complicated than simple ints. There's data, timestamps, and other methods to turn the data into other forms of data.
The Question: I have successfully implemented the dereference operator mentioned above. The problem is that when I use the ExpandingIterator and want to access one of the methods on the Data object, I end up writing
(*iterator).Method()
I would prefer to write
iterator->Method();
The solution to this problem seems obvious thus-far. I need to implement the -> operator. This initially seemed straightforward, but I'm afraid that I'm missing something (probably something quite obvious)
At first, I tried:
Data ExpandingIterator::operator->() const{
return **this; //Just call the regular dereference operator
}
But that left me with the error message: type 'Data' does not have an overloaded member 'operator ->'. A bit more research, and based on this answer here I believe there are a few possible solutions:
Can someone please help clear up misunderstanding (or lack of understanding) of how the -> operator is supposed to be implemented?
Upvotes: 1
Views: 363
Reputation: 70472
You can define a helper class within your iterator that can delegate the ->
operation to a Data
pointer.
class ExpandingIterator {
//...
struct DataPtr {
Data data;
DataPtr () {}
DataPtr (const Data &d) : data(d) {}
Data * operator -> () { return &data; }
}
//...
DataPtr operator -> () const { return **this; }
//..
};
Upvotes: 2
Reputation: 153955
To overload operator->()
you eventually need to arrive at an actually pointer, e.g., a T const*
for a suitable type T
. When you return something different than a pointer from operator->()
, the compiler will call operator->()
on the returned object.
From the sounds of it, it may be reasonable in your case to return a Data
object from ExpandingIterator::operator->()
which gets filled with the corresponding data at the given location. Of course, Data
would need another operator->()
which could return, e.g., a pointer to itself, i.e., this
assuming that Data
has the actual member functions you want to call.
In principle, you could have multiple indirections before you eventually arrive at an object you actually want to return a pointer to. However, it seems once you returned a Data
object you have an entity in your hand you want to call a member function on and, thus, returning a pointer to it should work. Note, that the rules for temporaries still apply, i.e., if you return a Data
object it will disappear at the end of the full expression.
Upvotes: 2