This is my code :
std::vector<int> vec = {1, 2, 3, 4, 5};
auto even = [=](int i) {
if (i % 2 == 1) {
return true;
}
return false;
};
auto square = [=](int i) {
return i * i ;
};
for (auto &item : vec | std::views::filter(even) | std::views::transform(square)) {
std::cout << item << std::endl;
}
I want to get the vec result through |
(pipe) such like this : 1 2 9 4 25
but compiler tells me
E:\Source Files\Jetbrains\Clion\moderncpp\main.cpp: In function 'int main()':
E:\Source Files\Jetbrains\Clion\moderncpp\main.cpp:21:84: error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
21 | for (auto &item : vec | std::views::filter(even) | std::views::transform(square)) {
| ^
mingw32-make[3]: *** [CMakeFiles\moderncpp.dir\build.make:81: CMakeFiles/moderncpp.dir/main.cpp.obj] Error 1
what could i do if i want to change my value in vector using pipe |
Thanks !
CodePudding user response:
Here you try taking a non-const
reference to an rvalue which isn't allowed:
for(auto &item : vec | ...
Either take it by const&
:
for(const auto &item : vec | ...
or by value:
for(auto item : vec | ...
what could i do if i want to change my value in vector
If you really want to change the values in the vector<int>
you could use the transform_view
to create a new vector<int>
that you move assign to vec
:
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto even = [](int i) { return i % 2 == 0; }; // bugfixed and no capture
auto square = [](int i) { return i * i; }; // no capture
// create transform_view
auto trans = vec | std::views::filter(even) | std::views::transform(square);
// populate a temporary vector that you assign to `vec`
vec = std::vector<int>(trans.begin(), trans.end());
for (auto& item : vec) {
std::cout << item << '\n';
}
}
With Range-v3 you could create the vector<int>
directly using ranges::to<std::vector<int>>()
. Unfortunately, this doesn't exist in the C 20 standard library (but will hopefully be added in the future):
#include <range/v3/all.hpp>
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto even = [](int i) { return i % 2 == 0; };
auto square = [](int i) { return i * i; };
vec = vec | ranges::views::filter(even)
| ranges::views::transform(square)
| ranges::to<std::vector>(); // using ranges::to
for (auto& item : vec) {
std::cout << item << '\n';
}
}
CodePudding user response:
I want to get the vec result through | (pipe) such like this :
1 2 9 4 25
It looks like you want to square the odd-valued elements in vec
, try this:
std::vector vec = {1, 2, 3, 4, 5};
std::ranges::for_each(
vec | std::views::filter([](auto& elem) { return elem % 2 == 1; }),
[](auto& elem) { elem *= elem; });
CodePudding user response:
what could i do if i want to change my value in vector using pipe |
You can transform the vector in-place using an algorithm like std::ranges::transform
, but you need to cut out the extra elements:
#include <iostream>
#include <ranges>
#include <vector>
#include <algorithm>
#include <concepts>
int main()
{
std::vector<int> vec = {1, 2, 3, 4, 5};
constexpr auto even = [](std::integral auto i) noexcept {
return i % 2 == 0;
};
constexpr auto square = [](auto i) noexcept {
return i * i;
};
// Create view.
constexpr auto my_view = std::views::filter(even)
| std::views::transform(square);
// Show the resulting view (4 16), without changing the source vector.
for (auto item : vec | my_view)
{ // ^^^^^^^^^^^^^
std::cout << item << ' ';
}
std::cout << '\n';
// Use an algorithm to transform the vector...
auto [ignored, it] = std::ranges::transform( vec | my_view
, vec.begin()
, std::identity{} );
// But erase the filtered out elements.
vec.erase(it, vec.end());
for (auto item : vec) // Outputs 4 16
{ // ^^^
std::cout << item << ' ';
}
std::cout << '\n';
}