I’m not sure if range_value_t will be in C++20 or not. If not, it can be spelled value_type_t<iterator_t<R>>. In any case, this is fine. It works, it’s pretty clear.

But sometimes, the underlying condition we want isn’t exactly that it’s the same type - maybe we want something convertible? For instance, if I’m writing my own vector class, I might want it to be constructible from any range convertible to the same value type right? That’s also pretty easy to write with concepts:

Again, this is fine. It works, it’s pretty clear. But then it’s easy to keep coming up with situations where you want slightly different mechanics. Maybe you go back to the original algorithm and it’s not really specific to ints and you want to generalize it to arbitrary numeric types? Do you write a new concept then?

That call fails, but it doesn’t fail the concept check - we deduce F as RvalueOnly, and Invocable<RvalueOnly, int> is satisfied… but then f(42) actually invokes the function as an lvalue, so it’s the wrong check.

In order to fix this, we’d have to either use the longest-form syntax with Invocable: