I have a vector of a class Planters which contain vectors of Plants. My goal is to return a vector of plants containing the plants from planter 1, followed by plants from planter 2, etc.
example: planter{{1,2,3,4}, {2,3,4,5}} should lead to {1,2,3,4,2,3,4,5}. note that the numbers represent plant objects. I'm trying to use join_view to flatten it but I am getting the error
error: class template argument deduction failed:
18 | plants = std::ranges::join_view(planterView);
| ^
/home/parallels/CMPT373/se-basic-cpp-template/lib/solutions/task05.cpp:18:52: error: no matching function for call to ‘join_view(std::ranges::ref_view<std::vector<ex4::Planter> >&)’
I have tried the following :
for (auto it : planters){
plants.insert(plants.end(), it.getPlants().begin(), it.getPlants().end());
}
This works however I am only allowed to use one loop (excluding loops inside STL function calls) and can only allocate memory once. The above approach allocates memory multiple times. How do I approach this?
my code:
std::vector<Plant> task05(std::vector<Planter> planters){
std::vector<Plant> plants;
auto planterView = std::views::all(planters);
std::views::transform(planterView, [](Planter planter){ return planter.getPlants();});
plants = ranges::views::all(std::ranges::join_view(planterView));
return plants;
}
Class:
struct Plant {
int plantiness = 0;
Plant(int plantiness)
: plantiness{plantiness}
{ }
bool
operator==(const Plant& other) const noexcept {
return plantiness == other.plantiness;
}
};
class Planter {
public:
Planter(std::initializer_list<Plant> plants)
: plants{plants}
{ }
const std::vector<Plant>&
getPlants() const noexcept {
return plants;
}
private:
std::vector<Plant> plants;
};
https://godbolt.org/z/T75anE15c
Firstly you go wrong here
std::transformis inplace butviews::transformis not and returns a view which you ignore, but this needs to be passed intojoin_view.Secondly, begin and end return different types, but the constructor of
std::vectorneeds these to have the same type, so you have to useviews::commonto achieve this.Thirdly, the deduced return type of the lamdba doesn't propagate the
const&-ness ofgetPlantsresulting in a copy. You have declare the return type asdecltype(auto).Also, you don't need to call
views::all. It will be automatically called when callingtransformand you should use thejoinadapter rather than thejoin_viewtype.Also, ranges are very ergonomic when used in a pipeline so just writing one expression spanning multiple lines is best practice.
Also, there's not much point wrapping
intandstd::vector<int>in structs. It's easy just to usestd::tuple,std::array,std::variant,std::optionaland never actually write your own types.