Home > Back-end >  Loop compiles but Range does not
Loop compiles but Range does not

Time:06-26

OrderProcessor::ProcessRange function in the code below accepts a range as an argument and iterates over it. When I try to call it with a range constructed with std::views::filter it does not compile, but when I copy and paste OrderProcessor::ProcessRange function implementation into the code it compiles:

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

namespace data
{
    struct Order
    {
    };
}

namespace app
{
    template <class R, class Value>
    concept range_over = std::ranges::range<R> &&
        std::same_as<std::ranges::range_value_t<R>, Value>;

    class OrderProcessor
    {
    public:

        void Process(const data::Order&) {}

        template <range_over<data::Order> Range>
        void ProcessRange(const Range& range)
        {
            for (const data::Order& order : range)
            {
                Process(order);
            }
        }
    };
}

int main()
{
    using namespace app;

    std::vector<data::Order> sample_orders;

    auto range = sample_orders | std::views::filter([](const data::Order&) -> bool { return true; });

    OrderProcessor processor;

    processor.ProcessRange(range); //-does not compile

    //But the following loop compiles:
    //for (const data::Order& order : range)
    //{
    //    processor.Process(order);
    //}
}

it also compiles if I remove std::views::filter, what can be the difference?

GCC errors:

prog.cc: In instantiation of 'void app::OrderProcessor::ProcessRange(const Range&) [with Range = std::ranges::filter_view<std::ranges::ref_view<std::vector<data::Order> >, main()::<lambda(const data::Order&)> >]' :
prog.cc : 51 : 27 : required from here
prog.cc : 32 : 13 : error : passing 'const std::ranges::filter_view<std::ranges::ref_view<std::vector<data::Order> >, main()::<lambda(const data::Order&)> >' as 'this' argument discards qualifiers[-fpermissive]
32 | for (const data::Order& order : range)
| ^ ~~
In file included from prog.cc : 2 :
/ opt / wandbox / gcc - 11.1.0 / include / c   / 11.1.0 / ranges : 1307 : 7 : note : in call to 'constexpr std::ranges::filter_view<_Vp, _Pred>::_Iterator std::ranges::filter_view<_Vp, _Pred>::begin() [with _Vp = std::ranges::ref_view<std::vector<data::Order> >; _Pred = main()::<lambda(const data::Order&)>]'
1307 | begin()
| ^ ~~~~
prog.cc : 32 : 13 : error : passing 'const std::ranges::filter_view<std::ranges::ref_view<std::vector<data::Order> >, main()::<lambda(const data::Order&)> >' as 'this' argument discards qualifiers[-fpermissive]
32 | for (const data::Order& order : range)
| ^ ~~
In file included from prog.cc : 2 :
/ opt / wandbox / gcc - 11.1.0 / include / c   / 11.1.0 / ranges : 1321 : 7 : note : in call to 'constexpr auto std::ranges::filter_view<_Vp, _Pred>::end() [with _Vp = std::ranges::ref_view<std::vector<data::Order> >; _Pred = main()::<lambda(const data::Order&)>]'
1321 | end()
| ^ ~~

CodePudding user response:

You just need to drop the const on the range argument to ProcessOrder(). A range may change when you iterate it - and apparently that's true for the filter view. Perhaps the library or the compiler could have guessed otherwise, but they don't.

Without the const - it compiles: https://godbolt.org/z/MnEczfTjG

Also note that if you make the range variable const to begin with, you'll be in trouble with your loop as well.

  • Related