Использование range-v3 для чтения списка чисел, разделенных запятыми
Я бы хотел использовать Ranges (я использую реализацию range-v3) для чтения входного потока, который представляет собой список чисел, разделенных запятыми. Без диапазонов обойтись тривиально, но... Я подумал, что это простой способ решить эту проблему:
auto input = std::istringstream("42,314,11,0,14,-5,37");
auto ints = ranges::istream_view<int>(input) | ranges::view::split(",");
for (int i : ints)
{
std::cout << i << std::endl;
}
Но это не компилируется. Я пробовал несколько вариантов этого, но, похоже, ничего не работает, я думаю, что это неправильно в нескольких отношениях. Может ли кто-нибудь объяснить мне, что я делаю неправильно, и объяснить, как это сделать?
Заранее спасибо!
2 ответа
Какой
ranges::istream_view<int>(input)
действительно создает диапазон, который является грубым эквивалентом этой сопрограммы (даже если вы не понимаете сопрограммы C++20, надеюсь, этот пример достаточно прост, чтобы понять суть):
generator<int> istream_view_ints(istream& input) {
int i;
while (input >> i) { // while we can still stream int's out
co_yield i; // ... yield the next int
}
}
Здесь два важных момента:
- Это диапазон
int
s, поэтому вы не можетеsplit
это на веревочке. - Это использует обычный поток
>>
, что не позволяет указывать собственный разделитель - он останавливается только на пробеле.
В целом, istream_view<int>(input)
дает вам ряд int
s, который, по вашему мнению, состоит из одного int
: просто 42
. Следующий ввод будет пытаться прочитать в,
и потерпеть неудачу.
Чтобы получить ввод с разделителями, вы можете использовать getlines
. Это даст вам рядstring
с указанным вами разделителем. Оно использует std::getline
внутренне. По сути, это сопрограмма:
generator<string> getlines(istream& input, char delim = '\n') {
string s;
while (std::getline(input, s, delim)) {
co_yield s;
}
}
А затем вам нужно преобразовать эти string
с к int
с. Что-то вроде этого должно помочь:
auto ints = ranges::getlines(input, ',')
| ranges::view::transform([](std::string const& s){ return std::stoi(s); });
std::string input = "42,314,11,0,14,-5,37";
auto split_view = ranges::view::split(input, ",");
даст ряд диапазонов:
{{'4', '2'}, {'3', '1', '4'}, {'1', '1'}, {'0'}, {'1', '4'}, {'-', '5'}, {'3', '7'}}
.
так что вы можете сделать:
std::string input = "42,314,11,0,14,-5,37";
auto split_view = ranges::view::split(input, ",");
for (auto chars : split_view) {
for (auto c : chars) {
std::cout << c;
}
std::cout << std::endl;
}