Можно ли сделать move_iterator из istream_iterator?

Рассмотрим следующий код:

typedef istream_iterator<char> char_itr ;
char_itr eos;

string ll("some text here");

istringstream line_in(ll);
char_itr start(line_in);

move_iterator<char_itr> mstart(start); // !!!
move_iterator<char_itr> meos(eos);
vector<char> vc(mstart, meos);

Выше код не будет компилироваться из-за строки (!!!):

error C2440: 'return' : cannot convert from 'const char' to 'char &&'

Но если вы замените mstart а также meos с start а также eosсоответственно (обычные итераторы) код скомпилируется. Почему я не могу сделать move_iterators?

РЕДАКТИРОВАТЬ: Для тех, кто интересуется, почему я хотел бы переместить символ из потока / строки. Актуальная проблема включает в себя более сложный тип данных, чем char какое копирование из строки следует избегать. char был использован просто для простоты, чтобы представить механизм, вызывающий ошибку.

2 ответа

Ранее в этом году обсуждалось это в группе новостей std-Discussion: https://groups.google.com/a/isocpp.org/forum/.

Похоже, что консенсус istream_iterator::reference является T const& для обеспечения соблюдения InputIterator контракт; то есть, чтобы пользователи не писали *it = value;, К сожалению, это также не позволяет перейти от кэшированного значения.

Как упоминалось выше, отправьте разрешение в LWG2106, код скомпилируется; к сожалению, потому что move_iterator::reference будет T const&& он будет молча делать неправильные вещи, скорее всего, вызывая конструктор копирования вашего типа.

поскольку istream_iterator изменяет кэшированное значение при увеличении, это (от языка POV) законно const_cast возвращенная ссылка на T&, К сожалению (опять же) это не помогает, так как нет простого способа вставить const_cast между istream_iterator а также move_iterator,

Возможные обходные решения:

  • написать свой istream_iterator с неконстантным reference ЬурейеЕ;
  • написать свой move_iterator выполнение const_cast;
  • написать вставку const_cast итератор;
  • используйте изменяемую оболочку вокруг типа значения.

Последний вариант удивительно прост:

template<class T>
  struct mutable_wrapper {
    T mutable value;
    operator T&() const { return value; }
  };
// ...
using itr = std::istream_iterator<mutable_wrapper<MyType>>;

Пример.

Смотря на istream_iterator::referenceмы видим, что это T const &, Разыменование итератора дает нам такую ​​ссылку. Но чтобы быть в состоянии отойти от чего-то, это что-то должно быть изменяемым. Вот что сообщение об ошибке пытается сказать вам.

Вы могли бы сделать move_iterator из istream_iterator, поместив некоторый пользовательский итератор, который хранит внутреннее (неконстантное) хранилище между ними.

Но почему вы хотите отойти от istream_iterator? Это однопроходные итераторы, и поэтому они почти не имеют внутреннего хранилища.

Другие вопросы по тегам