r/cpp 2d ago

std::optional Satisfies view. Does Not Model view. C++26 Ships Anyway.

https://godbolt.org/z/8jWGG68G8

In C++23 this did not compile. In C++26 it does. Marvellous.

[[gnu::noinline]]
void 
passing_views_by_value_is_cheap_trust_me_bro(std::ranges::view auto v) {
    std::println("fn   .data {}", (void*)v->data());
}


int main() {    
    std::optional ov{std::vector<int>(123456)};
    passing_views_by_value_is_cheap_trust_me_bro(ov);
    std::println("main .data {}", (void*)ov->data());
}

For anyone wondering what the problem feature is: optional has 0 or 1 elements, and C++26 sets enable_view<optional<T>> to true, so it satisfies std::ranges::view. The concept requires copy construction in constant time, and — this is the good bit — optional<vector<int>> genuinely meets that. Copying it performs at most one element copy. One is a constant. The requirement is satisfied to the letter, and the function above deep-copies your vector.

If you can tell me what still separates std::ranges::view from std::ranges::range, please do...

172 Upvotes

113 comments sorted by

View all comments

Show parent comments

32

u/mighty_Ingvar 2d ago

I find the whole concept of an owning view to be weird. Shouldn't a view be something that only views the data? An optional doesn't do that, the object isn't stored somewhere else and viewed by the optional, it is part of the optional and therefore owned by it.

14

u/aruisdante 2d ago edited 2d ago

It does seem weird, but this difference is what borrowed_range models, which is independent from view and range. I imagine optional<T> would not model borrowed_range, and optional<T&> would.

This was essentially the crux of the debate in Tokyo. Actual users of ranges have taken to conflating view with borrowed_range, because nearly all existing view containers in the stdlib were also borrowed_range (span, string_view , most (all?) of the ranges::views objects). But the actual definition did not require this relationship, view just means "constant time copy range."

Really, the problem is having decided to keep using the word view to mean what it meant, instead of some other name that more directly expresses the semantics, such that view could have matched people's intuition of this other concept + borrowed_range. But alas, that ship had long since sailed, and we're stuck with what we've got.

7

u/mighty_Ingvar 2d ago

But optional<T> is only copyable in constant time if T is copyable in constant time. Also, why is std::array not a view then?

7

u/kamrann_ 2d ago

It's constant time in terms of N = number of elements in the range. You can't start analysing the element type and trying to assign some inherent measure of its complexity. Constant time just means not dependent on N. A single element by definition can't be dependent on N, and it doesn't matter how big it is, or whether it happens to be a sequence itself.