Можно ли сделать чтение входных значений N более элегантным с помощью С++20?
Предположим, я хочу прочитать n целых чисел из стандартного потока ввода. Чтение:
Как прочитать N целых чисел в вектор?
Я считаю, что рекомендуемое решение в основном:
template<class InputIt, class Size, class OutputIt>
OutputIt copy_atmost_n(InputIt first, InputIt last, Size count, OutputIt result)
{
for (Size i = 0; i < count && first != last; ++i)
*result++ = *first++;
return result;
}
auto read_n(std::istream& is, std::size_t n) {
vector<int> result;
// possibly reserve n elements
copy_atmost_n(
std::istream_iterator<int>(is),
std::istream_iterator<int>(),
n,
std::back_inserter(result)
);
return result;
}
Мне это не нравится по следующим причинам:
- Использование
copy_atmost_n()
делает предположение о том, как отказ от «разыменования» итератора повлияетfirst
последующее значение. Но это предполагаемое поведение является скорее идиосинкразическим, чем общеизвестным. Я уверен, что это смутило бы многих разработчиков. - Нужна "постановочная" переменная.
- Повторение
std::istream_iterator<int>
.
Предоставляет ли C++20 и особенно диапазоны более приятный подход?
Примечание. Нет абсолютной необходимости возвращать
std::vector<int>
. Также можно использовать некоторую ленивую структуру, если это упрощает задачу.
1 ответ
Ответ должен быть † таким:
auto read_n(std::istream& is, std::size_t n) {
return std::ranges::istream_view<int>(is) | std::views::take(n);
}
если вы просто хотите ленивый диапазон. А затем собирая это жадно в
vector<int>
как вы считаете нужным.
† Но это пока не совсем работает из-за LWG 3408, но вскоре должно быть исправлено P2259, так что в конечном итоге это будет правильно.