неинформативная ошибка при использовании boost :: iterator_adaptor - PullRequest
3 голосов
/ 14 декабря 2010

Я пытаюсь обернуть istream с boost progress_display, используя boost::iterator_adaptor.То, что я написал, это:

class ifstreamWithProgress: public boost::iterator_adaptor <
  ifstreamWithProgress,
  char*,
  boost::use_default,
    boost::forward_traversal_tag > {
public:
//  ifstreamWithProgress(const char* fname_) {}
  ifstreamWithProgress(): iter(std::istream_iterator<char>()), pd(0)
  {}

  ifstreamWithProgress(const std::string& fname_): fname(fname_), fsize(0), pd(fsize) {
    std::ifstream file(fname.c_str(), std::ios::binary);
    fsize = file.tellg();
    file.seekg(0, std::ios::end);
    fsize = file.tellg() -  fsize;
    file.seekg(0, std::ios::beg);
    iter = std::istream_iterator<char>(file);
    pd.restart(fsize);
  }

  ~ifstreamWithProgress() {
    while( ++pd < fsize);
  }

  const std::istream_iterator<char> getRawIstream() const {
    return iter;
  }

private:
  std::string fname;
  friend class boost::iterator_core_access;
  std::istream_iterator<char> iter;
  std::streampos fsize;
  progress_display pd;

  void increments() {
    iter++;
    ++pd;
  }

  bool equal(const ifstreamWithProgress& rhs) const {
    return this->iter == rhs.getRawIstream();
  }
};

Это компилируется.Однако, когда я начал делать что-то вроде

  ifstreamWithProgress is("data.txt");
  ifstreamWithProgress eos;
  is != eos;

, я получаю ошибку во время компиляции, говорящую, что это не копируетсяЭто имеет некоторый смысл, потому что класс отображения является производным от boost::noncopyable.Однако я не понимаю, где происходит копирование.Любые указатели?

PS: сообщение об ошибке

1>c:\users\leon.sit\documents\myprojects\c++\general_models\phoenixdsm\phx\fileProgressBarWrapper.hpp(58) : error C2248: 'boost::noncopyable_::noncopyable::noncopyable' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'
1>        C:\Program Files\boost\boost_1_44\boost/noncopyable.hpp(27) : see declaration of 'boost::noncopyable_::noncopyable::noncopyable'
1>        C:\Program Files\boost\boost_1_44\boost/noncopyable.hpp(22) : see declaration of 'boost::noncopyable_::noncopyable'
1>        This diagnostic occurred in the compiler generated function 'ifstreamWithProgress::ifstreamWithProgress(const ifstreamWithProgress &)'

, которое не указывает нигде в источнике.Однако он компилируется после комментирования строки сравнения.

Ответы [ 2 ]

1 голос
/ 16 декабря 2010

Итераторы предназначены для облегченных объектов, которые можно копировать.Все стандартные утилиты, которые принимают итераторы, получают их как по значениям параметров.Неравенство operator !=, определяемое boost_adaptor, не является исключением.Отсюда это:

is != eos;

Совпадения:

bool operator != (ifstreamWithProgress, ifstreamWithProgress);

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

1 голос
/ 14 декабря 2010

Копирование не должно происходить где-либо, чтобы вызвать эту ошибку.Это простое отражение того факта, что компилятор должен сгенерировать конструктор копирования.Но для этого нужно также скопировать progress_display, что невозможно, так как конструктор копирования последнего является личным.

Вы можете обойти это, объявив указатель на член progress_display иопределить свой собственный конструктор копирования и = оператор.Например:

class ifstreamWithProgress: public boost::iterator_adaptor <
  ifstreamWithProgress,
  char*,
  boost::use_default,
    boost::forward_traversal_tag > {
public:
  ifstreamWithProgress() : pd(0) {
    pd = new progress_display(...);
  }

  ifstreamWithProgress::ifstreamWithProgress(const ifstreamWithProgress &r) : pd(0) {
    pd = new progress_display(...);
  }

  ~ifstreamWithProgress() {
    if (0 != pd) {
      delete pd;
    }
  }

  ifstreamWithProgress& operator= (const ifstreamWithProgress &r) {
    if (0 != pd) {
      delete pd;
    }
    pd = new progress_display(...);
    return *this;
  }

private:
  progress_display *pd;
};

Или вы можете использовать shared_ptr<progress_display>.

...