使用range-v3读取逗号分隔的数字列表

3

我希望使用区间(我使用范围-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;
}

但是这个无法编译。我已经尝试了很多变化,但似乎没有任何作用,我想这种方式有很多问题。请问有人能告诉我我做错了什么,并解释应该如何做吗?

先谢谢了!


1
“this fails so bad”是什么意思?当某个程序“失败得如此之糟”时,它到底是什么意思?它能编译吗?从编译生成的二进制文件能否执行?它会输出一些奇怪的数字吗?它会抛出异常吗?如何检测某个程序是否“失败得如此之糟”? - KamilCuk
@KamilCuk 是的,你说得对。我已经澄清它无法编译。 - bamse
2个回答

4

What

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
    }
}

这里有两个重要的点:

  1. 这是一组int的范围,因此您无法将其拆分成字符串。
  2. 它使用正常流>>,不允许您提供自己的定界符-它仅停止在空白处。

总之,istream_view<int>(input)会为您提供一组int的范围,在您的输入中,它只包含一个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;
    }
}

然后您需要将这些字符串转换为整数。以下类似的代码应该可以解决问题:

auto ints = ranges::getlines(input, ',')
          | ranges::view::transform([](std::string const& s){ return std::stoi(s); });

非常感谢@Barry的启发! :-) 遗憾的是,似乎不容易,甚至不可能,仅仅设置一个自定义分隔符来替代istream只能使用空格分隔输入的方式。我之前并不知道ranges::getlines,但是通过将其与istream一起使用,正如你所示的那样,很好地解决了我的问题。 - bamse

2
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;
}

感谢@Jarod42的回答。我询问的是如何处理istream输入,而不是字符串输入。但是您展示的字符串分割示例导致了一系列范围的启示,即使它没有回答我的问题。 :-) - bamse
我只是发现并解释了问题,没有给出解决方案。(我最初考虑将子范围缩小到std::string,然后在transform之后转换为int,但Barry提出的ranges::getlines更优越。) - Jarod42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接