Deborah C
Deborah C

Reputation: 147

Some C++20 ranges views not compatible with std::copy

In the code below, as it stands, doesn't compile. But replace std::views::take(2) with std::views::drop_while and the code compile. I do understand that the take_view and drop_while view do different things, non the less, it shouldn't matter if I want to take some or drop some, I still should be able to copy those elems into the container.

#include <ranges>
#include <vector>
#include <iostream>
#include <unordered_map>
using namespace std;

int main()
{
    //std::views::drop_while([](const int val){return val < 9;}) |

    vector v{1,2,3,4,5,6,7,4,8,9};   
    std::ranges::take_view res = v | std::views::filter([](const int val){return val %2 == 0;}) | std::views::transform([](const int val){return val*3;}) 
    |  std::views::take(2);
    decltype(v) filtered;
    std::copy(res.begin(),res.end(),std::back_inserter(filtered));
    for (const auto val : filtered)
    {
        std::cout << "val: " << val << '\n';
    }


    return 0;
}

Tried to look for explanation on the net. EDIT: Error:

main.cpp: In function ‘int main()’: main.cpp:23:14: error: no matching function for call to ‘copy(std::counted_iterator > >, main():: >, main():: >::_Iterator >, std::ranges::take_view > >, main():: >, main():: > >::_Sentinel, std::back_insert_iterator > >)’ 23 |
std::copy(res.begin(),res.end(),std::back_inserter(filtered)); | ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/string:40, from /usr/include/c++/11/bits/locale_classes.h:40, from /usr/include/c++/11/bits/ios_base.h:41, from /usr/include/c++/11/streambuf:41, from /usr/include/c++/11/bits/streambuf_iterator.h:35, from /usr/include/c++/11/iterator:66, from /usr/include/c++/11/ranges:43, from main.cpp:9: /usr/include/c++/11/bits/stl_algobase.h:611:5: note: candidate: ‘template constexpr _OI std::copy(_II, _II, _OI)’ 611 | copy(_II __first, _II __last, _OI __result) | ^~~~ /usr/include/c++/11/bits/stl_algobase.h:611:5: note: template argument deduction/substitution failed: main.cpp:23:14: note: deduced conflicting types for parameter ‘_II’ (‘std::counted_iterator

, main():: >, main():: >::_Iterator >’ and ‘std::ranges::take_view > >, main():: >, main():: > >::_Sentinel’) 23 | std::copy(res.begin(),res.end(),std::back_inserter(filtered)); | ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/11/iterator:66, from /usr/include/c++/11/ranges:43, from main.cpp:9: /usr/include/c++/11/bits/streambuf_iterator.h:325:5: note: candidate: ‘template typename __gnu_cxx::__enable_if::__value, std::ostreambuf_iterator<_CharT> >::__type std::copy(std::istreambuf_iterator<_CharT>, std::istreambuf_iterator<_CharT>, std::ostreambuf_iterator<_CharT>)’
325 | copy(istreambuf_iterator<_CharT> __first, | ^~~~ /usr/include/c++/11/bits/streambuf_iterator.h:325:5: note: template argument deduction/substitution failed: main.cpp:23:14: note: ‘std::counted_iterator > >, main():: >, main():: >::_Iterator >’ is not derived from ‘std::istreambuf_iterator<_CharT>’ 23 |
std::copy(res.begin(),res.end(),std::back_inserter(filtered)); | ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Upvotes: 3

Views: 500

Answers (1)

Toby Speight
Toby Speight

Reputation: 30925

The range res doesn't model Common Range, i.e. its begin() and end() have different types.

The easy solution is to simply use the range version of the algorithm instead:

    std::ranges::copy(res, std::back_inserter(filtered));

If you really need start and end (for a function such as std::accumulate() which is not yet rangeified), then we'll need to convert to a common range.

    auto common_res = res | std::views::common;
    std::copy(common_res.begin(), common_res.end(), std::back_inserter(filtered));

Full program:

#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    std::ranges::take_view res = std::views::iota(1,10)
        | std::views::filter([](const int val){return val %2 == 0;})
        | std::views::transform([](const int val){return val*3;})
        | std::views::take(2);

    std::vector<int> filtered;
    std::ranges::copy(res, std::back_inserter(filtered));
    for (const auto val : filtered) {
        std::cout << "val: " << val << '\n';
    }
}

Upvotes: 3

Related Questions