Home > Mobile >  Is const broken with std::views?
Is const broken with std::views?

Time:12-15

void foo(const auto& collection)
{
    *collection.begin() = 104;
}

int main()
{
    std::vector<int> ints {1, 2, 3, 4, 5};
    foo(ints); // Error, as it should be
    foo(ints | std::views::all); // Compiles and modifies the vector. Why?
    return 0;
}

Why is constness of lvalue reference completely ignored if an argument of a function is of type std::view?

Edit:
If, as you wrote in the comments, const view reference is similar to const pointer in this context, why does the code not compile if the same function takes a view constructed from an rvalue object as an argument?

std::vector<int> getVec()
{
    return std::vector{1, 2, 3, 4, 5};
}

void foo(const auto& collection)
{
    *collection.begin() = 104; // Error: assignment of read-only location
}

int main()
{
    foo(getVec() | std::views::all); // Nope!
    return 0;
}

CodePudding user response:

Views, despite the name, need not be non-modifiable. In general, how a class that represents a sequence of contained objects propagates const depends on what class gets used. And that's where things get weird.

See, the return type of views::all(e) changes depending on exactly what e is. If e is a glvalue (and is not itself a view), then it returns a ref_view of the range denoted by e. ref_view behaves as if it stores a pointer to the range it is given. Of course, if you have an R* member of a class, the const equivalent of that is R * const, not R const*. So ref_view cannot propagate const to the contained range.

However, if e is a prvalue (and again is not a view), then what all returns is an owning_view. This object actually stores a copy of e (well, it moves from it) as a member. This means that when you get a const owning_view, that const is propagated to that member. And since const vector<T> does propagate const, so too will a views::all(e) of a prvalue of vector.

  • Related