tags:

views:

48

answers:

2

A typical forward iterator is expected to implement following methods:

value_type& operator*();
value_type* operator->();

I'm writing a custom iterator for a custom container where user expects to see a value_type different from representation of the value inside a container. So when returning a value_type value to user I convert it from inner representation to user-expected value_type. It is easy to implement inside mentioned members.

Could you advice how to handle l-values? Where can I handle conversion of value_type to inner representation when user assigns values to iterator in syntax like *it = value_type(5)?

I thought of returning a functor but I dislike this idea becaues of non-usual syntax on caller's side.

+3  A: 

If you're returning a reference, then you can't convert and return a reference unless you store the converted value, at which point I begin to question the point of an internal representation. I'm not sure if what you want is even possible. An example of this is vector<bool>, which is legendary because it doesn't work properly. If the standards committee can't make such a container work, it's probably not a great idea.

DeadMG
+1  A: 

You might want to take a look into the implementation of the std::vector<bool> specialization iterators, as they tackle the same problem. Note that with time, the specialization has been frown upon mainly because it does not comply with the container requirements (the iterators don't provide references to the actual contained type, but a proxy value), and that will also be a problem with your implementation.

The other possible approach is using a regular container but having the stored type accept implement the assignment/conversions to and from the user expected types. If that is not possible with your current stored type, you can write a wrapper for it.

A simplified wrapper (you will need to work on it to make it work):

template <typename T, typename U>
class wrapper
{
public:
   typedef T store_type;
   typedef U value_type;
   wrapper() : stored() {}
   wrapper( value_type const & v ) 
      : stored( convert<store_type>(v) {}
   wrapper& operator=( value_type const & value ) { // or pass-by-value
      stored = convert<store_type>(value); // or however you can convert them
      return *this;
   }
   operator value_type() const { // I don't quite like this, if possible use explicit conversions
      return convert<value_type>(stored);
   }
private:
   store_type stored; // maybe storage is handled externally and this can be pointer/ref.
};
// For the simple test double<->int conversion static cast suffices
template <typename T, typename U>
T convert( U in ) {
   return static_cast<T>(in); 
}
int main() {
   std::vector< wrapper<double,int> > v;
   v.push_back( 10 );
   int x = v[0];
   v[0] = 5;

   std::vector< wrapper<int,double> > v2;
   v.push_back( 10.5 );
   double y = v2[0];
   v2[0] = 11.3;
}
David Rodríguez - dribeas
Could you please provide a sample of using such wrapper? How will methods look like?
flashnik
Do you have any other information on what the interface type and the store types might be?
David Rodríguez - dribeas
Just `value_type` and `stored_type`. It is a template parameters. Typically `stored_type` is `int*`. Also there is a `Wrapper` with members `value_type operator() (strored_type s)` and `stored_type operator() (value_type v)` but any other can be added.
flashnik
Thank you, I got the idea!
flashnik