为什么所有名单都被填充

时间:2016-06-06 19:15:36

标签: c++ regex list iterator istream-iterator

因此给定了定义:

typedef char Task;

struct Tache {
    char step;
    int duration;
    list<Task> precedentTask;
};

我为Tache编写了一个提取运算符:

istream& operator>>(istream& lhs, Tache& rhs) {
    string line;

    getline(lhs, line, '\n');

    stringstream ss(line);

    ss >> rhs.step;
    ss.ignore(numeric_limits<streamsize>::max(), '(');
    ss >> rhs.duration;
    ss.ignore(numeric_limits<streamsize>::max(), ')');

    const regex re("\\s*,\\s*([a-zA-Z])");
    string precedentTasks;

    getline(ss, precedentTasks);

    transform(sregex_token_iterator(cbegin(precedentTasks), cend(precedentTasks), re, 1), sregex_token_iterator(), back_insert_iterator<list<Task>>(rhs.precedentTask), [](const string& i) {
        return i.front();
    });

    return lhs;
}

然而,当我尝试将此提取运算符与istream_iterator一起使用时,precedentTask成员似乎会流入下一个元素。例如,给定:

stringstream seq("A(3)\nB(4),A\nC(2),A\nE(5),A\nG(3),A\nJ(8),B,H\nH(7),C,E,G\nI(6),G\nF(5),H");

list<Tache> allTaches{ istream_iterator<Tache>(seq), istream_iterator<Tache>() };

for (const auto& i : allTaches) {
    cout << i.step << ' ' << i.duration << ' ';
    copy(cbegin(i.precedentTask), cend(i.precedentTask), ostream_iterator<Task>(cout, " "));
    cout << endl;
}

Live Example

我得到了:

  

A 3
  B 4 A
  C 2 A A
  E 5 A A A
  G 3 A A A A
  J 8 A A A A B H
  H 7 A A A A B H C E G
  I 6 A A A B H C E G G
  F 5 A A A A B H C E G G H

而不是我的期望:

  

A 3
  B 4 A
  C 2 A
  E 5 A
  G 3 A
  J 8 B H
  H 7 C E G
  我6 G
  F 5 H

我是否滥用了sregex_token_iterator

1 个答案:

答案 0 :(得分:3)

这与正则表达式无关,而且与istream_iterator在幕后的内容有关:它只有一个T元素,当你递增时它会被读入:

  

istream_iterator& operator++();
  3 需要in_stream != 0
  4 效果*in_stream >> value
  5 返回*this

您的流操作符只是附加到rhs.precedentTask,但它不一定是空的。先清楚吧。这也不是istream_iterator问题,您的operator>>也必须能够在这种情况下工作:

Tache foo;
while (std::cin >> foo) {
    // ...
}

如果你所做的只是追加,那么第一个之后的每个后续Tache都会出错。您完全负责初始化对象的所有成员,并且您不应对其先前的值进行任何假设。

我建议用transform()替换一个循环:

sregex_token_iterator it(cbegin(precedentTasks), cend(precedentTasks), re, 1), end;
for (; it != end; ++it) {
    rhs.precedentTask.push_back(it->front());
}

或将其包装在范围内:

for (std::string match : sregex_matches(precedentTasks, re, 1)) {
    rhs.precedentTask.push_back(match.front());
}