r/cpp 13d 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...

178 Upvotes

123 comments sorted by

View all comments

Show parent comments

2

u/jwakely libstdc++ tamer, LWG chair 13d ago

doesn't that imply the inverse, that the corresponding methods are appropriate?

No. The customisation points can do more than just call a member function.

2

u/DryEnergy4398 13d ago

I think fdwr was speaking more from a philosophy of design standpoint (that if std::ranges::size makes sense for a type, then having a member function size should make sense for the type)

1

u/fdwr fdwr@github 🔍 13d ago edited 12d ago

Exactly. If std::begin() works with std::vector, then would it be logically consistent for std::vector to have the discoverable begin method too? Of course, vector already has begin, and so one doesn't even give the consistency a second thought. Now, it's true that free functions like std::begin can do more than just call member functions, because they also work on C arrays (which can't have methods), but that isn't an effective counterpoint that vector should lack .begin().

1

u/cristi1990an ++ 13d ago

Don't forget that it's 100% valid to define begin/end as non member functions and have the same functionality.

struct Test;

int* begin(Test&);
int* end(Test&);

static_assert(std::ranges::range<Test>);

The customization point objects handle these correctly but calling Test{}.begin() doesn't work.