我遇到了一个奇怪的问题。我有一个vector<pair<bool, int>>
,我需要从中读取(并且可能只写)该对的布尔值为true的向量元素。我正在使用增强范围滤波器和反向适配器来做到这一点。
但是,我注意到了适配器的顺序,即我是否使用了反转|过滤或过滤|逆转产生不同的结果。实际上,当我使用filter |当我使用迭代器到变换范围来改变对的布尔值时,然后在更改指向不同的向量元素之后的迭代器。当我使用reverse |时,这不会发生过滤。以下是演示此问题的代码。关于为什么会发生这种情况的任何想法都非常感谢!
#include <boost/range/adaptors.hpp>
#include <vector>
#include <utility>
#include <iostream>
using namespace boost::adaptors;
using container_type = std::vector<std::pair<bool,int>>;
struct to_include {
bool operator()(const std::pair<bool,int>& x) {
return x.first;
}
};
int main() {
container_type container;
/* element0: 1, 1 */
/* element1: 1, 2 */
/* element2: 1, 3 */
for(size_t i=0; i!=3; ++i) container.push_back(std::make_pair(true, i+1));
container_type container_cpy = container;
/* filter and then reverse */
auto fr = container | filtered(to_include()) | reversed;
auto fr_it1 = fr.begin();
auto fr_it2 = std::next(fr_it1);
fr_it2->first = false;
std::cout << "FILTER AND THEN REVERSE\n";
std::cout << fr_it2->first << " " << fr_it2->second << '\n'; /* prints (1,1) instead of (0,2) */
/* reverse and then filter */
auto rf = container_cpy | reversed | filtered(to_include());
auto rf_it1 = rf.begin();
auto rf_it2 = std::next(rf_it1);
rf_it2->first = false;
std::cout << "\nREVERSE AND THEN FILTER\n";
std::cout << rf_it2->first << " " << rf_it2->second << '\n'; /* prints (0,2) */
return 0;
}
答案 0 :(得分:1)
这是一个微妙的问题。这里的要点是,在修改fr_it2
指向的元素后,您还隐式修改fr_it1
,因为fr
是原始范围上的懒惰视图。这意味着需要重新计算transformed
过滤器。这是一个非常直观的属性,因为对于急切的STL范围,通过迭代器的修改不会修改迭代器本身,但对于惰性范围,这不再是真的!
事实上,如果使用“新鲜”迭代器打印整个fr
和rf
范围,您将看到它们的内容实际上是相同的。
fr_it2->first = false;
for (auto e : fr) std::cout << e.first << e.second << ";"; // prints 13;11
...
rf_it2->first = false;
for (auto e : rf) std::cout << e.first << e.second << ";"; // prints 13;11
Live Example 1。所以实际上中间元素确实被删除了!
我认为你不应该通过迭代器将元素修改为适应范围,而是通过迭代器将其修改到主容器中,如下所示:
auto fr_it1 = container.begin();
...
auto rf_it1 = container_cpy.begin();
Live Example 2。 如果这样做,您将得到一致的结果,两种方法都显示“0 2”。