Those are going to be used to implement range adaptors,
see D107098 for details.
Details
- Reviewers
• Quuxplusone zoecarver - Group Reviewers
Restricted Project - Commits
- rG89a7bdb1f37a: [libc++] Add the __bind_back and __compose helpers
Diff Detail
- Repository
- rG LLVM Github Monorepo
Unit Tests
Event Timeline
Marking "request changes" so it shows up correctly in queues; but there's nothing big or urgent among my comments. Just consider enabling in C++14 mode, and (almost certainly IMHO) include the new files in <functional>.
libcxx/include/__functional/bind_back.h | ||
---|---|---|
27 | Could this be > 11? | |
libcxx/include/__functional/compose.h | ||
25 | Same here: could this be > 11? | |
libcxx/test/libcxx/utilities/function.objects/func.bind.partial/bind_back.pass.cpp | ||
9 | If you do enable __bind_back back to C++14, then this line will need to change and you'll need to use more ::value and less _v in this test. | |
20 | What's the ruling on whether <foo> should include <__foo/internal_detail.h>? I know when we were originally debating the micro-headers, the idea was floated (but not necessarily agreed upon or even remarked upon) that <foo> should eventually be a simple mechanical listing of all <__foo/*.h>, i.e., if any <__foo/internal_detail.h> were missing from <foo>, we'd call that a bug.
If this is enough precedent for you, I think we should adopt it as official (unwritten) policy and this TODO should just get DONE. :) | |
326–333 | Nit: You could flip these around: auto ret = std::__bind_back(std::move(value), 1); using RetT = decltype(ret); static_assert( std::is_move_constructible<RetT>::value); // etc. | |
384 | Nit: Lines 386–390 are about whether the unspecified type's operator() is SFINAE-friendly. | |
libcxx/test/libcxx/utilities/function.objects/func.bind.partial/compose.pass.cpp | ||
61–71 | Maybe worth testing some ref-qualified member functions too? |
Address review comments except bumping the required Standard.
libcxx/include/__functional/bind_back.h | ||
---|---|---|
27 | I would agree because of the "dropping #ifs faster" story, but I think the benefit of using standard facilities (i.e. invoke instead of __invoke) outweighs that. WDYT? | |
libcxx/test/libcxx/utilities/function.objects/func.bind.partial/bind_back.pass.cpp | ||
9 | There isn't a huge benefit in doing this, since if Barry's paper gets in, bind_back would be enabled in C++20 (or 23) only. I'd basically rename it from __bind_back to bind_back and expose it publicly. | |
20 | Sold, let's mechanically include everything. I will still include __functional/compose.h in the compose.pass.cpp test, since there's no plan to make it part of <functional> in the spec. I'll still include it in <functional> just for consistency, but I think it's better to include the minimal header if we're testing a pure implementation detail. | |
libcxx/test/libcxx/utilities/function.objects/func.bind.partial/compose.pass.cpp | ||
61–71 | Yes, it is intentional. I think I should actually put it in a test that is specific to __perfect_forward, but I'm on the fence because I don't want to have the tests in three places once bind_back makes it to the standard (bind_front, bind_back and __perfect_forward). |
libcxx/include/__functional/bind_back.h | ||
---|---|---|
27 | I see cost-but-no-benefit to using _VSTD::invoke over _VSTD::__invoke. We have __invoke precisely so that we can use it in places where invoke wouldn't have been available until C++17. Also invoke is heavier-weight than __invoke; we'd rather use __invoke than invoke throughout the library. | |
libcxx/test/libcxx/utilities/function.objects/func.bind.partial/bind_back.pass.cpp | ||
9 | I doubt bind_back would be "DR'ed" back to C++20 at this point — but that doesn't stop libc++ from supporting it in C++20 anyway. Leaving __bind_back untested in '14 and '17 SGTM. |
Try to fix the modules build
libcxx/include/__functional/bind_back.h | ||
---|---|---|
27 | __perfect_forward uses is_invocable, the wording for bind_front uses std::invoke, and so does the wording for bind_back in the paper. It just feels better to use something that everybody knows the semantics of at first glance (std::invoke) over something that might or might not be exactly what you'd expect (you can't know without looking). I think that's the primary reason why I find it easier to understand what's going on when std::invoke is used over __invoke. IMO, we should strive to use standard APIs when we can and when it makes sense to do that, instead of using internal variants of those. |
Could this be > 11?
Could it be > 11 if you used _VSTD::__invoke instead of _VSTD::invoke?
(Besides just feeling nicer, keeping our dependencies minimal might one day help us clean up old code faster. As soon as we drop support for C++11, the whole #if goes away. Whereas if you make it depend on C++20, then we have to keep the #if in place for another 9 years until we drop support for C++17.)