为什么所有列表都被填充
Why Are All List's Being Populated
所以给定定义:
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;
}
我得到:
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 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
I 6 G
F 5 H
我是否滥用了 sregex_token_iterator
?
这与正则表达式无关,而与 istream_iterator
在幕后所做的一切有关:它只有一个 T
元素,当您递增它时它会读入该元素:
istream_iterator& operator++();
3 Requires: in_stream != 0
.
4 Effects: *in_stream >> value
.
5 Returns: *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());
}
所以给定定义:
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;
}
我得到:
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 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
I 6 G
F 5 H
我是否滥用了 sregex_token_iterator
?
这与正则表达式无关,而与 istream_iterator
在幕后所做的一切有关:它只有一个 T
元素,当您递增它时它会读入该元素:
istream_iterator& operator++();
3 Requires:in_stream != 0
.
4 Effects:*in_stream >> value
.
5 Returns:*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());
}