Пользовательский итератор, который преобразует значения перед их сохранением

Ожидается, что типичный прямой итератор реализует следующие методы:

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

Я пишу собственный итератор для пользовательского контейнера, где пользователь ожидает увидеть value_type, отличное от представления значения внутри контейнера. Поэтому, возвращая пользователю значение value_type, я преобразовываю его из внутреннего представления в ожидаемое пользователем value_type. Это легко реализовать внутри упомянутых членов.

Не могли бы вы посоветовать, как обращаться с l-значениями? Где я могу обработать преобразование value_type во внутреннее представление, когда пользователь присваивает значения итератору в синтаксисе, таком как *it = value_type(5)?

Я думал вернуть функтор, но мне не нравится эта идея из-за необычного синтаксиса на стороне вызывающей стороны.


person flashnik    schedule 19.05.2010    source источник


Ответы (2)


Возможно, вы захотите взглянуть на реализацию итераторов специализации std::vector<bool>, так как они решают ту же проблему. Обратите внимание, что со временем специализация не одобрялась главным образом потому, что она не соответствует требованиям к контейнеру (итераторы предоставляют ссылки не на фактический содержащийся тип, а на прокси-значение), и это также будет проблемой для вашего реализация.

Другой возможный подход заключается в использовании обычного контейнера, но при наличии хранимого типа accept реализует назначение/преобразование в ожидаемые пользователем типы и из них. Если это невозможно с вашим текущим сохраненным типом, вы можете написать для него оболочку.

Упрощенная оболочка (вам нужно будет поработать над ней, чтобы она заработала):

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;
}
person David Rodríguez - dribeas    schedule 19.05.2010
comment
Не могли бы вы предоставить пример использования такой оболочки? Как будут выглядеть методы? - person flashnik; 19.05.2010
comment
Есть ли у вас какая-либо другая информация о том, каким может быть тип интерфейса и типы хранилища? - person David Rodríguez - dribeas; 19.05.2010
comment
Только value_type и stored_type. Это параметры шаблона. Обычно stored_type равно int*. Также есть Wrapper с членами value_type operator() (strored_type s) и stored_type operator() (value_type v), но можно добавить любые другие. - person flashnik; 19.05.2010

Если вы возвращаете ссылку, вы не можете преобразовать и вернуть ссылку, если не сохраните преобразованное значение, и в этот момент я начинаю сомневаться в точке внутреннего представления. Я не уверен, возможно ли то, что вы хотите. Примером этого является vector<bool>, легендарный, потому что он не работает должным образом. Если комитет по стандартам не может заставить такой контейнер работать, это, вероятно, не очень хорошая идея.

person Puppy    schedule 19.05.2010