Является ли это использование обратных вызовов идиоматическим? - PullRequest
0 голосов
/ 24 мая 2018

Я заметил общий шаблон в моем коде

std::string line;
if (!in || !std::getline(in, line)) {
  throw line_read_error(in,line_counter);
}
++line_counter;
std::istringstream sin{line};

// ...read from sin...

if (!sin.eof()) {
  sin.clear();
  throw incomplete_read_error(in,line_counter,sin.tellg());j
}

То, что я читал из строки, было различным в каждом месте, но настройки и проверка после чтения были идентичны.

Я учел это, создав объект для хранения моего in потока и line_counter, и передав обратный вызов для тела:

class LineReader {
  std::istream& in;
  size_t line_counter;
public:
  template <typename Function>
  void with_next_line(Function callback) {
    std::string line;
    if (!in || !std::getline(in, line)) {
      throw line_read_error(in,line_counter);
    }
    ++line_counter;
    std::istringstream sin{line};

    callback(sin);

    if (!sin.eof()) {
      sin.clear();
      throw incomplete_read_error(in,line_counter,sin.tellg());j
    }
  }
  // ...
}

Изменив мои использования на

line_reader.with_next_line([/*...*/](auto& sin){
  // ...read from sin...
});

Это, конечно, меньше повторений, но все же немного неловко.

Однако меня действительно беспокоит то, будет ли другим людям легко следовать, как я на самом деле пытаюсьсделать мой код как можно более разборчивым

1 Ответ

0 голосов
/ 24 мая 2018

обычный способ настройки + очистки состоит в том, чтобы иметь объект, конструктор которого выполняет настройку, а деструктор выполняет очистку (RAII).

Однако , очистка, которую вы хотите сделать, состоит в том, чтобы бросать, если вы не читали до конца - и бросать из деструктора - зло, плохо и неправильно.Это означает, что вы не можете использовать RAII в этом конкретном случае.

Если действительно важно выполнить проверку, то код, который вы используете, будет применять его.Если это просто «хорошая идея», то я думаю, что два вызова (до и после), вероятно, немного чище, чем лямбда.(Я бы не стал беспокоиться о std::move(sin) - использование движения на самом деле ничего здесь не добавляет.)

...