Reputation: 73
I am currently working through examples from the book Expert C++.
In chapter 7, they offer the following code for mapping a function to a matrix:
#include <vector>
#include <ranges>
#include <iostream>
using IntMatrix = std::vector<std::vector<int>>;
int count_evens(const std::vector<int>& number_line) {
return std::count_if(number_line.begin(),
number_line.end(), [](int num){return num % 2 == 0;});
}
std::vector<int> count_all_evens(const IntMatrix& numbers)
{
return numbers | std::ranges::views::transform(count_evens); // ERROR APPEARS HERE AT |
}
int main()
{
IntMatrix m{{1, 2, 3}, {4, 5, 6}};
for (auto item : count_all_evens(m)) {
std::cout << item << " ";
}
std::cout << std::endl;
return 0;
}
I am getting an error on line 14 that says:
could not convert 'std::ranges::views::__adaptor::operator|<const std::vector<std::vector<int> >&>((* & numbers), std::ranges::views::transform.std::ranges::views::__adaptor::_RangeAdaptor<std::ranges::views::<lambda(_Range&&, _Fp&&)> >::operator()<int (&)(const std::vector<int, std::allocator<int> >&)>(count_evens))' from 'std::ranges::transform_view<std::ranges::ref_view<const std::vector<std::vector<int> > >, int (*)(const std::vector<int>&)>' to 'std::vector<int>'
Does anyone else have this issue? I am using the g++10 compiler.
Upvotes: 6
Views: 5789
Reputation: 41
Today I read a book "Functional Programming in C++" and met the same issue.
After spending a couple of hours, I found out it was related to the library "ranges".
The complete library should be: https://github.com/ericniebler/range-v3 instead of std::ranges. Be careful on the namespaces.
Maybe "C++20 ranges are the core subset of range-v3", they are sometimes mixed up... (Source: https://www.reddit.com/r/cpp/comments/kueb7n/what_are_the_differences_between_boostrange/)
The code worked for me, C++ 14/17/20, with g++ 10.3.0.
#include <iostream>
#include <vector>
#include <iomanip>
#include <range/v3/view/transform.hpp>
#include <range/v3/range/conversion.hpp>
auto vector_plus_one(const std::vector<uint32_t>&) -> std::vector<uint32_t>;
int main(int argc, char* argv[])
{
std::vector<uint32_t> v_in { 1, 2, 3 };
for (auto &n : v_in) {
std::cout << std::setw(5) << n;
}
std::cout << std::endl;
auto v_out = vector_plus_one(v_in);
for (auto &n : v_out) {
std::cout << std::setw(5) << n;
}
std::cout << std::endl;
return 0;
}
uint32_t elementwise_plus_one(const uint32_t& input)
{
return input + 1;
}
std::vector<uint32_t> vector_plus_one(const std::vector<uint32_t>& v_input)
{
return v_input | ranges::views::transform(elementwise_plus_one) | ranges::to_vector;
}
Upvotes: 4
Reputation: 10526
Use ranges::copy()
following code compiles with g++10 (C++20) and outputs
1 2
ranges::copy() accepts as argument a range and an iterator to the beginning of the output.
#include <vector>
#include <ranges>
#include <iostream>
#include <algorithm>
using namespace std;
using IntMatrix = vector<vector<int> >;
int count_evens(const vector<int>& number_line) {
return std::count_if(number_line.begin(),
number_line.end(), [](int num){return num % 2 == 0;});
}
vector<int> count_all_evens(const IntMatrix& numbers)
{
auto r = numbers | ranges::views::transform(count_evens);
int n = r.size();
vector<int> v(n);
ranges::copy(r, begin(v));
return v;
}
int main()
{
IntMatrix m{{1, 2, 3}, {4, 5, 6}};
for (auto item : count_all_evens(m)) {
std::cout << item << " ";
}
std::cout << std::endl;
return 0;
}
Upvotes: 2
Reputation: 275510
std::vector<int> count_all_evens(const IntMatrix& numbers)
{
auto view = numbers | std::ranges::views::transform(count_evens);
return {view.begin(), view.end()};
}
there is a proposal to make this suck less.
std::vector<int> count_all_evens(const IntMatrix& numbers)
{
auto view = numbers | std::ranges::views::transform(count_evens);
return std::ranges::to<std::vector<int>>(view);
}
You can also get fancy
template<class Range>
struct to_container {
Range&& r;
template<class Container>
operator Container()&&{ return {r.begin(), r.end()}; }
};
template<class Range>
to_container(Range&&)->to_container<Range>;
std::vector<int> count_all_evens(const IntMatrix& numbers)
{
return to_container{ numbers | std::ranges::views::transform(count_evens) };
}
Upvotes: 8