如何使用 boost::range::adaptors::transformed 而不是 std::unordered_set?
How to use boost::range::adaptors::transformed over std::unordered_set?
我正在尝试在 std::unordered_set 上使用 boost::adaptors::transformed,但即使在相当小的实验中似乎也会产生奇怪的行为。
我在 Ubuntu 16.04 和 gcc 5.4.0 上使用 Boost 1.58.0。
范围初始化后添加的元素在迭代范围时未列出:
#include <iostream>
#include <vector>
#include <unordered_set>
#include <boost/range/adaptor/transformed.hpp>
struct double_int
{
typedef int result_type;
int operator()(int x) const { return x * 2; }
};
int main()
{
std::unordered_set<int> set;
for(int i = 0; i < 5; ++i)
set.insert(i); //adding ints to set
auto range = set | boost::adaptors::transformed(double_int());
set.insert(10); //adding some other int
//this produces: '8 0 2 4 6'
for(auto i : range)
std::cout << i << std::endl;
//this produces: '10 4 0 1 2 3'
for(auto i : set)
std::cout << i << std::endl;
//element 10 is not doubled!
return 0;
}
遵循与其他标准容器(如 std::list)相同的方案,按预期工作,将后者添加的元素加倍。
更奇怪的是,如果集合使用以下方式初始化:
std::unordered_set<int> set = {0,1,2,3,4,5};
范围迭代仅给出“10”,而容器的“10 0 1 2 3 4 5”
谁能告诉我这个例子有什么问题吗?
我真的看不出问题所在:
Your exact sample code(实时)打印:
8 20 6 4 0 2
4 10 3 2 0 1
这似乎是您应该期待的。
10 8 6 4 2 0
5 4 3 2 1 0
想法:
可以Undefined Behaviour分配模板表达式:
auto range = set | boost::adaptors::transformed(double_int());
因为 double_int()
可能保存在 transformed
适配器中 BY REFERENCE(未检查)。
看看这是否为您解决了问题:
for (auto i : set | boost::adaptors::transformed(double_int()))
std::cout << i << " ";
transformed
不会将对范围的引用存储为范围;它在 the range adaptor's construction.
时获取范围的 begin
/end
迭代器
当您稍后在构造适配器后插入到集合中时,新元素可能不在插入之前由旧 begin/end
迭代器分隔的范围内。或者,更糟糕的是,如果插入会触发重新散列,则插入将使所有迭代器失效。
我正在尝试在 std::unordered_set 上使用 boost::adaptors::transformed,但即使在相当小的实验中似乎也会产生奇怪的行为。
我在 Ubuntu 16.04 和 gcc 5.4.0 上使用 Boost 1.58.0。
范围初始化后添加的元素在迭代范围时未列出:
#include <iostream>
#include <vector>
#include <unordered_set>
#include <boost/range/adaptor/transformed.hpp>
struct double_int
{
typedef int result_type;
int operator()(int x) const { return x * 2; }
};
int main()
{
std::unordered_set<int> set;
for(int i = 0; i < 5; ++i)
set.insert(i); //adding ints to set
auto range = set | boost::adaptors::transformed(double_int());
set.insert(10); //adding some other int
//this produces: '8 0 2 4 6'
for(auto i : range)
std::cout << i << std::endl;
//this produces: '10 4 0 1 2 3'
for(auto i : set)
std::cout << i << std::endl;
//element 10 is not doubled!
return 0;
}
遵循与其他标准容器(如 std::list)相同的方案,按预期工作,将后者添加的元素加倍。
更奇怪的是,如果集合使用以下方式初始化:
std::unordered_set<int> set = {0,1,2,3,4,5};
范围迭代仅给出“10”,而容器的“10 0 1 2 3 4 5”
谁能告诉我这个例子有什么问题吗?
我真的看不出问题所在:
Your exact sample code(实时)打印:
8 20 6 4 0 2
4 10 3 2 0 1
这似乎是您应该期待的。
10 8 6 4 2 0
5 4 3 2 1 0
想法:
可以Undefined Behaviour分配模板表达式:
auto range = set | boost::adaptors::transformed(double_int());
因为 double_int()
可能保存在 transformed
适配器中 BY REFERENCE(未检查)。
看看这是否为您解决了问题:
for (auto i : set | boost::adaptors::transformed(double_int()))
std::cout << i << " ";
transformed
不会将对范围的引用存储为范围;它在 the range adaptor's construction.
begin
/end
迭代器
当您稍后在构造适配器后插入到集合中时,新元素可能不在插入之前由旧 begin/end
迭代器分隔的范围内。或者,更糟糕的是,如果插入会触发重新散列,则插入将使所有迭代器失效。