在C++ std::ranges 中,如何从views::join 结果构建映射?

问题描述 投票:0回答:1

我在 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 来构造映射节点,但我无法真正从所有标准库内部了解太多。

仅使用一层“嵌套”范围按预期工作。因此,仅当嵌套范围级别连接并转换为地图时,才会出现此问题。

如何使第二个代码按预期编译并工作?

c++ g++ std std-ranges c++23
1个回答
0
投票

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>();
© www.soinside.com 2019 - 2024. All rights reserved.