我在 C+23 模式下使用 GCC 14。在下面的代码中,我创建了成对视图的视图,然后用views::join将其展平并放入向量中:
auto c = std::ranges::views::iota(1, 5)
| std::ranges::views::transform([](int const v){
return std::ranges::views::iota(1, 3)
| std::ranges::views::transform([v](int const w){
return std::make_pair(v, std::format("[{}/{}]", v, w));
});
})
| std::ranges::views::join
| std::ranges::to<std::vector>();
结果是一个向量对。
现在,我想创建一个映射(或 unordered_map),而不是成对的向量。从一系列对构建地图应该可行(正如我在旧问题中学到的那样)。但这里不能编译:
auto c = std::ranges::views::iota(1, 5)
| std::ranges::views::transform([](int const v){
return std::ranges::views::iota(1, 3)
| std::ranges::views::transform([v](int const w){
return std::make_pair(v, std::format("[{}/{}]", v, w));
});
})
| std::ranges::views::join
| std::ranges::to<std::map>();
不幸的是,编译器输出对我来说并不能真正理解。我从中得到的只是它无法调用 std::construct_at 来构造映射节点,但我无法真正从所有标准库内部了解太多。
仅使用一层“嵌套”范围按预期工作。因此,仅当嵌套范围级别连接并转换为地图时,才会出现此问题。
如何使第二个代码按预期编译并工作?
libstdc++ 目前没有实现
std::map
的范围构造函数,即 map(std::from_range_t, R&&)
,并且由于您构造的嵌套范围不是 common_range,ranges::to
将调度 (2.1.4) 到第一个默认构造的 std::map
,然后通过 c.emplace(c.end(), *it)
将元素放置到地图中。
请注意,大多数情况下希望在序列容器(例如
emplace()
)上调用 vector
,而不是 map
,因为后者的 emplace()
不需要接受迭代器作为第一个参数。但是,由于 map::emplace()
是一个不受约束的函数,因此仍然会调用它并导致硬错误。
解决方法是使用
views::common
将连接范围转换为 common_range
,因此可以使用经典的 map
构造函数构造 map(InputIt first, InputIt last)
。
auto c = std::views::iota(1, 5)
| std::views::transform([](int const v){
return std::views::iota(1, 3)
| std::views::transform([v](int const w){
return std::make_pair(v, std::format("[{}/{}]", v, w));
});
})
| std::views::join
| std::views::common
| std::ranges::to<std::map>();