展平包含结构向量的类向量

cal*_*rul 2 c++ stl-algorithm c++20 std-ranges

Planters我有一个包含 s 向量的类向量Plant。我的目标是返回一个植物向量,其中包含来自 Planter 1 的植物,然后是来自 Planter 2 的植物,依此类推。\n示例:planter{{1,2,3,4}, {2,3,4,5}}应该导致{1,2,3,4,2,3,4,5}. 请注意,数字代表植物对象。我试图用join_view它来压平它,但我收到了错误

\n
error: class template argument deduction failed:\n   18 |         plants = std::ranges::join_view(planterView);\n      |                                                    ^\n/home/parallels/CMPT373/se-basic-cpp-template/lib/solutions/task05.cpp:18:52: error: no matching function for call to \xe2\x80\x98join_view(std::ranges::ref_view<std::vector<ex4::Planter> >&)\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n

我已经尝试过以下操作:

\n
for (auto it : planters){\n  plants.insert(plants.end(), it.getPlants().begin(), it.getPlants().end());\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是可行的,但是我只允许使用一个循环(不包括 STL 函数调用内的循环)并且只能分配内存一次。上述方法多次分配内存。我该如何处理这个问题?

\n

我的代码:

\n
std::vector<Plant> task05(std::vector<Planter> planters){\n    std::vector<Plant> plants;\n    auto planterView = std::views::all(planters);\n    std::views::transform(planterView, [](Planter planter){ return planter.getPlants();});\n    plants = ranges::views::all(std::ranges::join_view(planterView));\n    return plants;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

班级:

\n
struct Plant {\n  int plantiness = 0;\n\n  Plant(int plantiness)\n    : plantiness{plantiness}\n      { }\n\n  bool\n  operator==(const Plant& other) const noexcept {\n    return plantiness == other.plantiness;\n  }\n};\n\n\nclass Planter {\npublic:\n  Planter(std::initializer_list<Plant> plants)\n    : plants{plants}\n      { }\n\n  const std::vector<Plant>&\n  getPlants() const noexcept {\n    return plants;\n  }\n\nprivate:\n  std::vector<Plant> plants;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

Tom*_*ton 6

std::vector<Plant> task05(std::vector<Planter> planters)
{
    auto plants = planters
        | std::views::transform([](Planter const& planter) -> decltype(auto) { return planter.getPlants();})
        | std::views::join
        | std::views::common
        ;
    return std::vector<Plant>(plants.begin(), plants.end());
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/T75anE15c

首先你这里出错了

auto planterView = std::views::all(planters);
std::views::transform(planterView, [](Planter planter){ return planter.getPlants();});
Run Code Online (Sandbox Code Playgroud)

std::transformis inplace 但views::transform不是,并返回一个您忽略的视图,但这需要传递到join_view.

其次,begin 和 end 返回不同的类型,但是 的构造函数std::vector需要它们具有相同的类型,所以你必须使用views::common来实现这一点。

第三,推导的 lamdba 返回类型不会传播生成副本const&的性质。getPlants您已将返回类型声明为decltype(auto).


另外,您不需要打电话views::all。调用时会自动调用transform,您应该使用join适配器而不是join_view类型。

此外,范围在管道中使用时非常符合人体工程学,因此只编写一个跨越多行的表达式是最佳实践。

此外,没有太多的点包装intstd::vector<int>结构。只需使用std::tuplestd::arraystd::variant、就很容易std::optional,而无需实际编写自己的类型。

  • 顺便说一句,“views::transform(&amp;Planter::getPlants)”要好得多:它避免了在 lambda 中意外按值获取对象的错误,而且在这种情况下,“getPlants”返回一个引用,因此您会意外复制它也在那里。另外,_因为_您现在返回一个值,所以生成的“join”最终成为一个非常见的输入范围 - 如果转换返回一个引用,它将是一个常见的双向范围。 (2认同)