Search code examples
c++stdstd-ranges

Why can't a view be assigned with the same type of the view?


Why can't I (re)assign the value for a view with the same type of the view?

Demo: https://godbolt.org/z/aqdh7ohva

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

int main()
{
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6 };

    const bool strategy_check_for_zero = true;

    auto selected = v | std::views::filter([=](const auto& v) { return !strategy_check_for_zero || v != 0; });

    // Impossible to do; why?
    selected = v | std::views::filter([=](const auto& v) { return true; });

    std::ranges::copy(selected, std::ostream_iterator<int>{std::cout, ", "});
    std::cout << '\n';
}

Well, in real code, it is more like this:

auto selected = v | std::views::filter([=](const auto& v) { return !strategy_check_for_zero || v != 0; });

if (selected.empty()) {
    selected = v | std::views::filter([=](const auto& v) { return true; });
}

I want to keep the code in question as simple as possible.


Solution

  • Why I can't (re)assign the value for a view even with the same type of the view?

    Simple. It's not the same type.

    Chaining views together produces a distinct type for the requested view.

    If the view actually is the same type, your code will compile.

    #include <iostream>
    #include <ranges>
    #include <vector>
    
    int main()
    {
        std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6 };
    
        const bool strategy_check_for_zero = true;
    
        auto lambda = [=](const auto& v) { return !strategy_check_for_zero || v != 0; };
        
        auto selected = v | std::views::filter(lambda);
        selected = v | std::views::filter(lambda);
    
        std::ranges::copy(selected, std::ostream_iterator<int>{std::cout, ", "});
        std::cout << '\n';
    }