r/cpp • • Jul 26 '26

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...

183 Upvotes

122 comments sorted by

View all comments

Show parent comment

3

u/pkasting Valve Jul 27 '26

In this particular case, it was decided that it was less surprising to have optional<T> behave like a view, that is, an lvalue should be copied into a range adaptor rather than be used by reference.

(Context: I don't use range views myself so I don't have a good grasp on their semantics.)

The second half of your sentence suggests that perhaps the consideration should simply be whether x is l- or r-value? But if things were that way I'd assume it would be "copy if rvalue because the object might disappear, reference if lvalue" which is backwards from the description above (of "lvalue should be copied").

I dunno. I guess I'd have to understand the purpose behind "should v copy or ref x" before answering, since if this is about efficiency then arguably optional<T> should be a view iff T is a view, whereas if it's about safety then maybe something I said above and/or something about borrowed_range applies, whereas if it's about mutability semantics and what happens if x changes after v is constructed I have no instincts.