在C++和range-v3中,如何首先转换一个视图,然后将其转换为映射?

huangapple go评论66阅读模式
英文:

In C++ and range-v3, how to first transform a view and then convert it to a map?

问题

如何将任何范围作为输入,首先将其元素转换为元组,然后保存在std::map中,使用ranges::to

这段代码有效,创建了一个元组的向量:

#include <range/v3/all.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>

int main() { 
        auto v = ranges::views::iota(3, 10)
                | ranges::views::transform([](auto const &v){ return std::make_tuple(v, v*2); })
                | ranges::to<std::vector>();    
        fmt::print("{}\n", v);
}

vector替换为map,我期望得到一个映射(其中元组的第一个元素变为键,第二个元素变为它们的值),但是代码无法编译:

#include <range/v3/all.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>

int main() { 
        auto v = ranges::views::iota(3, 10)
                | ranges::views::transform([](auto const &v){ return std::make_tuple(v, v*2); })
                | ranges::to<std::map>();       
        fmt::print("{}\n", v);
}

我得到以下错误消息:

test.cpp:11:10: error: invalid operands to binary expression ('invoke_result_t<ranges::views::transform_base_fn, ranges::iota_view<int, int>, (lambda at test.cpp:9:30)>' (aka 'transform_view<ranges::iota_view<int, int>, (lambda at test.cpp:9:30)>' and 'detail::to_container_fn<detail::from_range<std::map>>' (aka 'closure<ranges::detail::from_range<std::map>, ranges::detail::to_container::fn<ranges::detail::from_range<std::map>>>)

注:我在互联网上没有找到很多使用ranges::to<map>的示例,但在这个答案中:https://stackoverflow.com/a/74433668 中有一个有效的代码,将ranges::views::zip的结果转换为映射。由于zip生成"类似元组"的元素,我期望我的代码也能工作,但显然并不那么简单。

编译器是Clang++版本15.0.6,ranges是当前的主分支。

英文:

Having any range as an input, how to first convert its elements to tuples and then save them in a std::map with ranges::to?

This code works and creates a vector of tuples:

#include &lt;range/v3/all.hpp&gt;
#include &lt;fmt/format.h&gt;
#include &lt;fmt/ranges.h&gt;

int main() { 
        auto v = ranges::views::iota(3, 10)
                | ranges::views::transform([](auto const &amp;v){ return std::make_tuple(v, v*2); })
                | ranges::to&lt;std::vector&gt;();    
        fmt::print(&quot;{}\n&quot;, v);
}

Replacing vector by map, I'd expect to receive a map instead (with first elements of the tuples becoming keys and second elements becoming their values), but the code doesn't compile:

#include &lt;range/v3/all.hpp&gt;
#include &lt;fmt/format.h&gt;
#include &lt;fmt/ranges.h&gt;

int main() { 
        auto v = ranges::views::iota(3, 10)
                | ranges::views::transform([](auto const &amp;v){ return std::make_tuple(v, v*2); })
                | ranges::to&lt;std::map&gt;();       
        fmt::print(&quot;{}\n&quot;, v);
}

I get:
test.cpp:11:10: error: invalid operands to binary expression (&#39;invoke_result_t&lt;ranges::views::transform_base_fn, ranges::iota_view&lt;int, int&gt;, (lambda at test.cpp:9:30)&gt;&#39; (aka &#39;transform_view&lt;ranges::iota_view&lt;int, int&gt;, (lambda at test.cpp:9:30)&gt;&#39;) and &#39;detail::to_container_fn&lt;detail::from_range&lt;std::map&gt;&gt;&#39; (aka &#39;closure&lt;ranges::detail::from_range&lt;std::map&gt;, ranges::detail::to_container::fn&lt;ranges::detail::from_range&lt;std::map&gt;&gt;&gt;&#39;))

Notes: I didn't find many examples of using ranges::to&lt;map&gt; in the internet, but in this answer: https://stackoverflow.com/a/74433668 there's working code where the result of ranges::views::zip is converted to a map. Since zip produces "tuple-like" elements, I expected my code to work too, but apparently it's not that straightforward.

Compiler is Clang++ v. 15.0.6, ranges is current master.

答案1

得分: 1

你需要一个std::pair,而不是std::tuple示例链接):

auto m = ranges::views::iota(3, 10)
       | ranges::views::transform([](auto const &v){ return std::make_pair(v, v*2); })
       | ranges::to<std::map>;

总之,像这样是可以的:

std::vector<std::pair<int, int>> v;
std::map<int, int> M(v.begin(), v.end());

但像这样是不可以的:

std::vector<std::tuple<int, int>> v;
std::map<int, int> M(v.begin(), v.end());

或者,更简单地,如评论中建议的:

std::map<int, int> P{{std::pair<int, int>{}}};  // 可行
std::map<int, int> T{{std::tuple<int, int>{}}}; // 错误
英文:

You need a std::pair, not a std::tuple (working example):

auto m = ranges::views::iota(3, 10)
       | ranges::views::transform([](auto const &amp;v){ return std::make_pair(v, v*2); })
       | ranges::to&lt;std::map&gt;;

After all, while something like this is fine,

std::vector&lt;std::pair&lt;int, int&gt;&gt; v;
std::map&lt;int,int&gt; M(v.begin(), v.end());

something like this is not

std::vector&lt;std::tuple&lt;int, int&gt;&gt; v;
std::map&lt;int,int&gt; M(v.begin(), v.end());

Or, more simply as suggested in a comment,

std::map&lt;int,int&gt; P{{std::pair&lt;int, int&gt;{}}};  // OK
std::map&lt;int,int&gt; T{{std::tuple&lt;int, int&gt;{}}}; // Error

huangapple
  • 本文由 发表于 2023年4月7日 02:12:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75952542.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定