The following example compiles with gcc and fails with clang. I believe clang is correct but can't prove it. ======= begin example ============= #include <ranges> void foo() { std::ranges::iota_view iota(2, 10); iota.begin(); } ======== end example ============== Clang complains that iota_view doesn't have a begin() member (which it does). I think the reason is that the constraint is evaluated before iota_view is fully defined. gcc evaluates lazily so it doesn't stumble on the problem. The circular chain is: view_interface<iota_view> is instantiated as a base class of iota_view. Clearly iota_view isn't defined at this stage, it's just a forward-declared name. view_interface instantiates iterator_t, which is an alias to std::__detail::__range_iter_t. __range_iter_t instantiates __ranges_begin. __ranges_begin requires that its template parameter is a __member_begin<> (among other options, but this is the valid one here). __member_begin requires that the type (iota_view) have a begin() function. But the type isn't defined yet. I believe clang is correct, mostly because I believe concept evaluation should be eager and not lazy, not because I know it for a fact. Apologies for posting a clang issue here, I wouldn't if gcc could get asan+coroutines working. The problem will hit gcc if it implements eager evaluation too.
Concept evaluation is lazy, not eager. See [temp.inst]/18.
This makes sense, according to my very limited ability to understand the standard. I reflected it to the clang bug here: https://bugs.llvm.org/show_bug.cgi?id=47509.
This is a clang bug.