[libcxx-commits] [PATCH] D107098: [libc++] Implement the underlying mechanism for range adaptors
Zoe Carver via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jul 29 16:49:43 PDT 2021
zoecarver added inline comments.
================
Comment at: libcxx/include/__functional/bind_back.h:1
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
----------------
Quuxplusone wrote:
> High-level question: Why is this so complicated? All it needs to do AFAICT is just take the N arguments passed to it (for N=1 in C++20, but arguably we might see N>1 at some point), keep them in a tuple of `args...`, and then later take a `range auto&& lhs` and call the bound function `__f(lhs, args...)`. This doesn't feel like it ought to involve such a generic name as `__invoke_shuffle`. Is this overengineered, or what am I missing?
As I mentioned in discord, I have a much simpler implementation (that still allows us to have N arguments):
```
template<class _Tuple, class _Idxs = typename __make_tuple_indices<tuple_size<_Tuple>::value>::type>
struct __bind_back_op;
template<class _Tuple, size_t... _Idxs>
struct __bind_back_op<_Tuple, __tuple_indices<_Idxs...>> {
template <class _Fn, class _T2, class ..._Args>
_LIBCPP_HIDE_FROM_ABI
static constexpr auto __call(_Fn&& __f, _T2&& __t, _Args&& ...__args)
noexcept(noexcept(_VSTD::invoke(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)..., get<_Idxs>(__t)...)))
-> decltype( _VSTD::invoke(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)..., get<_Idxs>(__t)...))
{ return _VSTD::invoke(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)..., get<_Idxs>(__t)...); }
};
template <class _Fn, class ..._Args, class = _EnableIf<
conjunction_v<
is_constructible<decay_t<_Fn>, _Fn>,
is_move_constructible<decay_t<_Fn>>,
is_constructible<decay_t<_Args>, _Args>...,
is_move_constructible<decay_t<_Args>>...
>
>>
_LIBCPP_HIDE_FROM_ABI
constexpr auto __bind_back(_Fn&& __f, _Args&&... __args)
{
auto __t = tuple<decay_t<_Args>...>(__args...);
return __perfect_forward<__bind_back_op<decltype(__t)>, _Fn, tuple<decay_t<_Args>...>>(_VSTD::forward<_Fn>(__f), __t);
}
```
================
Comment at: libcxx/include/__ranges/range_adaptor.h:30
+template <class _Tp>
+struct __range_adaptor_closure { };
+
----------------
Why does this need to be a template?
================
Comment at: libcxx/include/__ranges/transform_view.h:422
+ inline constexpr auto transform = __transform_adaptor{};
+} // end namespace views
+
----------------
Quuxplusone wrote:
> In `all.h`, we create a nested namespace `views::__all`, place `struct __fn` in there, and then define the niebloid itself in
> ```
> inline namespace __cpo {
> inline constexpr auto all = __all::__fn{};
> } // namespace __cpo
> ```
> (all this basically to avoid unintentional ADL when `views::all` is passed as a function argument). If there's no technical reason to diverge here, please stick to that pattern; it'll make it easier to tell what's significant in this PR.
Not sure if this is UB, but we can actually see this trigger a ODR violation like so:
```
namespace std { namespace views {
struct dummy {
friend void transform() { }
};
}}
```
(If it's not UB we should definitely add those as tests.)
---
Refs (why we put all niebloids into their own inline namespace): https://stackoverflow.com/questions/50010074/why-does-range-v3-put-its-function-objects-into-an-inline-namespace and https://github.com/ericniebler/range-v3/pull/423
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D107098/new/
https://reviews.llvm.org/D107098
More information about the libcxx-commits
mailing list