Several span constructors use enable_if which is verbose. Replace these with
concepts or requires expressions.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Thanks for working on this! In general I prefer concepts over enable_ifs. Unfortunately some of our supported compilers don't have proper concepts support yet. We could use #ifs to guard against that, however IMO that would make the code unneeded ugly. Alternatively we wait until we only support compilers with concepts support.
@ldionne Do you know when AppleClang 13 will be released and whether it has concepts support?
(I want to discuss this before doing a review.)
libcxx/include/span | ||
---|---|---|
237 |
I benchmarked enable_if_t versus _EnableIf versus requires over at https://reviews.llvm.org/D108216#inline-1037983 a couple days ago, and it seemed that requires was about 20% slower than enable_if_t/_EnableIf. What evidence led you to the "and slow" part of your comment? |
libcxx/include/span | ||
---|---|---|
237 | Sorry, I was a bit aggressive/strong in my commit wording here: I've adjusted that now. I have not benchmarked enable_if_t vs requires in this commit, so I've omitted the speed remark. It surprises me a bit that requires is that much slower. I'd be interested to see an extension of your benchmark to account for enable_if_t when used as a default template parameter (e.g. does the number of templates make things go "really bad" after some threshold?). |
Thanks for some context. I started poking around in span last night as I came across this recent libc++ bug. It made me realize there are several missing constraints for span, which motivated a move to requires clauses first to make things not as verbose in fixing all of the constraints.
Thanks a lot for your interest in fixing this. Since we have been shipping std::span and we do support compilers that don't implement concepts yet, I'd like to push back against this change *for the time being*.
What I suggest is that you implement the changes discussed in https://bugs.llvm.org/show_bug.cgi?id=51443 using enable_if_t, and then we revisit this change as soon as all supported compilers implement concepts, which should be the case within a couple months. When that's the case, this patch will have all my support. Does that seem reasonable?
Seems very reasonable and what I'd recommend as well. I'll move forward with implementing http://wg21.link/p1394 using enable_if_t and as a follow-up I'll dig into the paper for the conditional explicitness of the constructors as talked about in the bug. We'll revisit this patch once we drop support for compilers that don't support concepts.
libcxx/include/span | ||
---|---|---|
237 | @Quuxplusone @ldionne how do you feel about revisiting this PR now that concepts should be fine to use in <span>? As it stands, we have a mix of enable_if_t vs concepts in some C++20 code in libc++ -- with most of the C++20-code being concepts and <span> being some of the former. |
libcxx/include/span | ||
---|---|---|
237 | We're still testing buildkite configurations (on Apple targets) where libcpp-no-concepts is a thing. IMO it will be appropriate to migrate things to Concepts only after someone lands a patch removing libcpp-no-concepts from the tests and _LIBCPP_HAS_NO_CONCEPTS from the code. If your hypothesis is that "by the time Clang 15 ships, these platforms will have Concepts support," then ok cool, make a PR to remove libcpp-no-concepts and see if people agree about that; then let's revisit this after that lands. :) |
Thanks for bringing this up again!
Arthur indeed had a benchmark concepts were slower. If easily done it would be nice to run this benchmark again. Compiler writers had years to optimize SFINAE, but concepts are fairly new. So I expect compiler writers to improve the speed processing concepts for the next years.
From a readability and maintainability point of view I prefer concepts.
Based on this comment I started reviewing, but the patch needs a rebase before reviewing. Feel free to wait until @ldionne agrees that we still want this improvement.
libcxx/include/span | ||
---|---|---|
467–468 | These spaces look odd. | |
468 | I was wondering why not using __is_span_compatible_container_v<_Container, _Tp>, but it seems __is_span_compatible_container no longer exists. So I stopped reviewing here. When we want to use this patch it needs to be rebased first. |
I would support exploring this -- unless enable_if is significantly faster, I think we should go for the readability and diagnostics improvement.
libcxx/include/span | ||
---|---|---|
209 | Could you rename this to __span_compatible_sentinel_for to keep the naming scheme of sized_sentinel_for and friends? | |
454–455 | Wouldn't that also work? | |
479–480 | Same here. | |
608 | Is there a reason we don't just use decltype(auto) as the return type and drop the trailing return type completely? |
Address philnik's comments
libcxx/include/span | ||
---|---|---|
454–455 | Yes, it works, but loses the symmetry with the next function template below (constrained by __span_array_convertible<const _OtherElementType, element_type>). I originally had it as you suggested. I'll make that change and we can let others decide which they prefer; I have a slight preference towards what you suggested because it's terser. | |
608 | No reason. Just switched to decltype(auto) since we have existing use of that in variant, and some of ranges, etc. |
LGTM with comment.
libcxx/include/span | ||
---|---|---|
608 | I think it's actually confusing to use decltype(auto) here since it suggests that there's some value-category preservation going on, when there really is none. I would just use auto instead. |
Just landed this with cb48ed38b8d09ef9cfa1f7258342d0379f169074. I accidentally did it from a different branch, so this review didn't auto-close. Sorry about that. Can someone elaborate on how to manually close this review? The docs at https://llvm.org/docs/Phabricator.html seem to suggest there's a Close Revision button, but I'm not seeing it.
When you submit a comment there's an Add Action... drop down, there you can close the revision.
As mentioned the commit was landed, but from the wrong branch so it wasn't closed automatically.
Could you rename this to __span_compatible_sentinel_for to keep the naming scheme of sized_sentinel_for and friends?