I'm trying to check if all values in nested vector are same/unique. I wrote this program (simplified, but same error):
#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>
auto main() -> int
{
std::vector<std::vector<int>> vectors_of_ints {
{1, 2, 3},
{4, 5, 6}
};
auto get_vectors = [](const std::vector<int>& v) { return v; };
auto get_ints = [](const int& i) { return i; };
auto all_ints = vectors_of_ints
| std::views::transform(get_vectors)
| std::views::join
| std::views::transform(get_ints);
auto status = std::ranges::adjacent_find(all_ints, std::not_equal_to{}) != std::ranges::end(all_ints);
return status;
}
but I'm getting this error:
<source>:22:44: error: no match for call to '(const std::ranges::__adjacent_find_fn) (std::ranges::transform_view<std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::vector<int> > >, main()::<lambda(const std::vector<int>&)> > >, main()::<lambda(const int&)> >&, std::not_equal_to<void>)'
22 | std::cout << std::ranges::adjacent_find(all_ints, std::not_equal_to{}) != std::ranges::end(all_ints);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...] // too long to post
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/ranges_base.h:594:13: required for the satisfaction of 'forward_range<_Range>' [with _Range = std::ranges::transform_view<std::ranges::join_view<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > >, main::._anon_112> >, main::._anon_113>&]
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/concepts:67:28: note: 'std::forward_iterator_tag' is not a base of 'std::input_iterator_tag'
67 | concept derived_from = __is_base_of(_Base, _Derived)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 1
Which concludes with: std::forward_iterator_tag is not a base of std::input_iterator_tag.
I would like to understand the problem I'm having here and how to fix that.
std::ranges__adjacent_findrequires aforward_rangeas input, but yourall_intsis only aninput_range. From cppreference:std::ranges::range_reference_t<Range>is the return type of an element of a range of typeRange. Because you transformvector_of_intswith yourget_vectors, an element of the resulting range isstd::vectorand thusstd::ranges::range_reference_tis not of reference type (See demo ). Note this happens only because auto follows the template argument deduction rules and does not deduce reference. Ifget_vectorsto return a reference tovectorinstead, you can usedecltype(auto):or specify the return type of the lambda explicitly.
Or the simple
works.
If you really want to copy the contents, consider creating a new vector from
all_ints:In C++23
std::ranges::tosimplifies this process and mitigates all copies to the end:See demo