tbb::blocked_range does not fulfill the c++20 concept std::ranges::range
Summary
One would think, based on the name that a tbb::blocked_range<T> fulfills the c++20 concept std::ranges::range, similar to a std::views::iota(tbb_range.begin(), tbb_range.end()). This is not the case, as far as I can tell, because tbb::blocked_range<T> returns a value type from tbb::blocked_range<T>::begin(). That value type is not an iterator because it cannot be de-referenced. std::views::iota deals with this with an exposition only class that wraps around the value type that is implicitly convertible to the value type. tbb::blocked_range<T> should return a similar wrapper so that tbb::blocked_range<T>s are actual c++20 ranges.
Version
tbb v2021.8.0
Observed Behavior
static_assert(std::ranges::range<tbb::blocked_range<std::size_t>>) fails
Expected Behavior
static_assert(std::ranges::range<tbb::blocked_range<std::size_t>>) passes
@dbs4261,
Thank you for your question.
blocked_range class was not initially designed to be a range in a C++20 meaning. It can only be used as an input for TBB parallel algorithms like parallel_for that currently do not support C++ ranges. Even for the blocked_range<iterator> that models the C++20 range in fact, it still can be used as the input for parallel algorithms unchanged. blocked_range piped with some other C++20 view cannot be used as the input since it does not model the TBB range .
Could you please share more details on when you believe it may be useful to have blocked_range<size_t> modeling the std::ranges::range concept?
@kboyarinov,
As for what I had in mind, I was actually looking to do something like this to get a more pythonic for loop. It would actually be really handy for use with the templated blocked_nd_range.
for (auto [p, r, c]: std::ranges::views::cartesian_product(r.pages(), r.rows(), r.cols())) {
...
}
I think the main thing to focus on is that I made this comment because I assumed that something with a begin and end that was called a range would fulfill the concept. I don't think that assumption is unreasonable, but I totally understand that blocked_range predates c++ ranges. I brought up std::ranges::views::iota because it does basically the same thing as a blocked_range. And I think adding this functionality is doable in a backwards compatible way.
As an aside, In my mind range::is_divisible() range::(R&, split) and range::(R&, proportional_split) make more sense as part of the Splittable named requirements.