Skip to content

[libcxx] renames some template type parameters #76540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions libcxx/docs/Contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ other implementations (e.g. system headers), the test in
``libcxx/test/libcxx/system_reserved_names.gen.py`` contains the list of
reserved names that can't be used.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with the change itself, but I question the added value of the documentation. Indeed, this naming scheme works well for e.g. algorithms where the iterators (or predicates, or whatever) don't have any semantics associated to them. However, in other parts of the code, it may convey more information to call the iterator parameter something other than its iterator category. I think it would be better to let people make the right naming decision based on what their code does. However, in cases where we're e.g. writing a new algorithm, folks would end up starting from (or getting inspiration from) code that consistently has the naming we want, so this might end up not being an issue at all.

Basically, I have a slight concern that documenting this naming scheme is going to be too strict, since there are cases where this naming scheme is not what we want. But either way I'm fine with this.

Maybe rewording to

We generally use the following names to refer to various template type parameters:

would alleviate my concern.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 -- the new documentation is great, but IMO should make it clear that these names are used when more specific names are not available, i.e. it's not a 100% requirement to use this naming scheme. I think adding "generally" would pretty much solve this, but I could also suggest adding a note like:

This naming scheme should be used for consistency in all cases where the types don't have any semantics associated with them and thus using a more specific name is not possible.


We use the following names to refer to various tempalate type parameters:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for adding documentation!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We use the following names to refer to various tempalate type parameters:
We use the following names to refer to various template type parameters:


* ``_Iter``, to refer to an iterator type. Some alterations are used if multiple
iterators with different categories appear in the same template:
* ``_InIter`` to disambiguate input iterators
* ``_ForwardIter`` to disambiguate input iterators
* ``_BiIter`` to disambiguate input iterators
* ``_RandomIter`` to disambiguate input iterators
* ``_ContgiuousIter`` to disambiguate input iterators
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* ``_ContgiuousIter`` to disambiguate input iterators
* ``_ContiguousIter`` to disambiguate input iterators

* ``_OutIter`` to disambiguate output iterators
* ``_Sent``, to refer to sentinels
* ``_Func``, to refer to arbitrary invocable objects
* ``_Pred``, to refer to predicates
* ``_Comp``, to refer to comparators
* ``_Proj``, to refer to projections
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about adding the common _Tp and _Up?


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment that older code may use other conventions. For example in format I use _OutIt

Unqualified function calls are susceptible to
`argument-dependent lookup (ADL) <https://en.cppreference.com/w/cpp/language/adl>`_.
This means calling ``move(UserType)`` might not call ``std::move``. Therefore,
Expand Down
66 changes: 36 additions & 30 deletions libcxx/include/__algorithm/fold.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,80 +37,86 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 23

namespace ranges {
template <class _Ip, class _Tp>
template <class _Iter, class _Tp>
struct in_value_result {
_LIBCPP_NO_UNIQUE_ADDRESS _Ip in;
_LIBCPP_NO_UNIQUE_ADDRESS _Iter in;
_LIBCPP_NO_UNIQUE_ADDRESS _Tp value;

template <class _I2, class _T2>
requires convertible_to<const _Ip&, _I2> && convertible_to<const _Tp&, _T2>
requires convertible_to<const _Iter&, _I2> && convertible_to<const _Tp&, _T2>
_LIBCPP_HIDE_FROM_ABI constexpr operator in_value_result<_I2, _T2>() const& {
return {in, value};
}

template <class _I2, class _T2>
requires convertible_to<_Ip, _I2> && convertible_to<_Tp, _T2>
requires convertible_to<_Iter, _I2> && convertible_to<_Tp, _T2>
_LIBCPP_HIDE_FROM_ABI constexpr operator in_value_result<_I2, _T2>() && {
return {std::move(in), std::move(value)};
}
};

template <class _Ip, class _Tp>
using fold_left_with_iter_result = in_value_result<_Ip, _Tp>;
template <class _Iter, class _Tp>
using fold_left_with_iter_result = in_value_result<_Iter, _Tp>;

template <class _Fp, class _Tp, class _Ip, class _Rp, class _Up = decay_t<_Rp>>
template <class _Func, class _Tp, class _Iter, class _Rp, class _Up = decay_t<_Rp>>
concept __indirectly_binary_left_foldable_impl =
convertible_to<_Rp, _Up> && //
movable<_Tp> && //
movable<_Up> && //
convertible_to<_Tp, _Up> && //
invocable<_Fp&, _Up, iter_reference_t<_Ip>> && //
assignable_from<_Up&, invoke_result_t<_Fp&, _Up, iter_reference_t<_Ip>>>;

template <class _Fp, class _Tp, class _Ip>
convertible_to<_Rp, _Up> && //
movable<_Tp> && //
movable<_Up> && //
convertible_to<_Tp, _Up> && //
invocable<_Func&, _Up, iter_reference_t<_Iter>> && //
assignable_from<_Up&, invoke_result_t<_Func&, _Up, iter_reference_t<_Iter>>>;

template <class _Func, class _Tp, class _Iter>
concept __indirectly_binary_left_foldable =
copy_constructible<_Fp> && //
invocable<_Fp&, _Tp, iter_reference_t<_Ip>> && //
__indirectly_binary_left_foldable_impl<_Fp, _Tp, _Ip, invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>;
copy_constructible<_Func> && //
invocable<_Func&, _Tp, iter_reference_t<_Iter>> && //
__indirectly_binary_left_foldable_impl<_Func, _Tp, _Iter, invoke_result_t<_Func&, _Tp, iter_reference_t<_Iter>>>;

struct __fold_left_with_iter {
template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp>
template <input_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Tp,
__indirectly_binary_left_foldable<_Tp, _Iter> _Func>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto
operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) {
using _Up = decay_t<invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>;
operator()(_Iter __first, _Sent __last, _Tp __init, _Func __f) {
using _Up = decay_t<invoke_result_t<_Func&, _Tp, iter_reference_t<_Iter>>>;

if (__first == __last) {
return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), _Up(std::move(__init))};
return fold_left_with_iter_result<_Iter, _Up>{std::move(__first), _Up(std::move(__init))};
}

_Up __result = std::invoke(__f, std::move(__init), *__first);
for (++__first; __first != __last; ++__first) {
__result = std::invoke(__f, std::move(__result), *__first);
}

return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), std::move(__result)};
return fold_left_with_iter_result<_Iter, _Up>{std::move(__first), std::move(__result)};
}

template <input_range _Rp, class _Tp, __indirectly_binary_left_foldable<_Tp, iterator_t<_Rp>> _Fp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) {
template <input_range _Rp, class _Tp, __indirectly_binary_left_foldable<_Tp, iterator_t<_Rp>> _Func>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Func __f) {
auto __result = operator()(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f));

using _Up = decay_t<invoke_result_t<_Fp&, _Tp, range_reference_t<_Rp>>>;
using _Up = decay_t<invoke_result_t<_Func&, _Tp, range_reference_t<_Rp>>>;
return fold_left_with_iter_result<borrowed_iterator_t<_Rp>, _Up>{std::move(__result.in), std::move(__result.value)};
}
};

inline constexpr auto fold_left_with_iter = __fold_left_with_iter();

struct __fold_left {
template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp>
template <input_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Tp,
__indirectly_binary_left_foldable<_Tp, _Iter> _Func>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto
operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) {
operator()(_Iter __first, _Sent __last, _Tp __init, _Func __f) {
return fold_left_with_iter(std::move(__first), std::move(__last), std::move(__init), std::ref(__f)).value;
}

template <input_range _Rp, class _Tp, __indirectly_binary_left_foldable<_Tp, iterator_t<_Rp>> _Fp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) {
template <input_range _Rp, class _Tp, __indirectly_binary_left_foldable<_Tp, iterator_t<_Rp>> _Func>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Func __f) {
return fold_left_with_iter(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f)).value;
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace __par_backend {
inline namespace __serial_cpu_backend {

template <class _RandomAccessIterator, class _Fp>
template <class _RandomAccessIterator, class _Func>
_LIBCPP_HIDE_FROM_ABI optional<__empty>
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Func __f) {
__f(__first, __last);
return __empty{};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace __par_backend {
inline namespace __thread_cpu_backend {

template <class _RandomAccessIterator, class _Fp>
template <class _RandomAccessIterator, class _Func>
_LIBCPP_HIDE_FROM_ABI optional<__empty>
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Func __f) {
__f(__first, __last);
return __empty{};
}
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__algorithm/ranges_copy_backward.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _Ip, class _Op>
using copy_backward_result = in_out_result<_Ip, _Op>;
template <class _InIter, class _OutIter>
using copy_backward_result = in_out_result<_InIter, _OutIter>;

namespace __copy_backward {
struct __fn {
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__algorithm/ranges_copy_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _Ip, class _Op>
using copy_if_result = in_out_result<_Ip, _Op>;
template <class _InIter, class _OutIter>
using copy_if_result = in_out_result<_InIter, _OutIter>;

namespace __copy_if {
struct __fn {
Expand Down
12 changes: 6 additions & 6 deletions libcxx/include/__algorithm/ranges_copy_n.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _Ip, class _Op>
using copy_n_result = in_out_result<_Ip, _Op>;
template <class _InIter, class _OutIter>
using copy_n_result = in_out_result<_InIter, _OutIter>;

namespace __copy_n {
struct __fn {
Expand All @@ -55,10 +55,10 @@ struct __fn {
return {__ret.first, __ret.second};
}

template <input_iterator _Ip, weakly_incrementable _Op>
requires indirectly_copyable<_Ip, _Op>
_LIBCPP_HIDE_FROM_ABI constexpr copy_n_result<_Ip, _Op>
operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const {
template <input_iterator _InIter, weakly_incrementable _OutIter>
requires indirectly_copyable<_InIter, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr copy_n_result<_InIter, _OutIter>
operator()(_InIter __first, iter_difference_t<_InIter> __n, _OutIter __result) const {
return __go(std::move(__first), __n, std::move(__result));
}
};
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/__algorithm/ranges_find.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ struct __fn {
}
}

template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, class _Proj = identity>
requires indirect_binary_predicate<ranges::equal_to, projected<_Ip, _Proj>, const _Tp*>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip
operator()(_Ip __first, _Sp __last, const _Tp& __value, _Proj __proj = {}) const {
template <input_iterator _Iter, sentinel_for<_Iter> _Sent, class _Tp, class _Proj = identity>
requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Tp*>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter
operator()(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) const {
return __find_unwrap(std::move(__first), std::move(__last), __value, __proj);
}

Expand Down
14 changes: 7 additions & 7 deletions libcxx/include/__algorithm/ranges_find_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _Ip, class _Sp, class _Pred, class _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr _Ip __find_if_impl(_Ip __first, _Sp __last, _Pred& __pred, _Proj& __proj) {
template <class _Iter, class _Sent, class _Pred, class _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr _Iter __find_if_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
for (; __first != __last; ++__first) {
if (std::invoke(__pred, std::invoke(__proj, *__first)))
break;
Expand All @@ -41,12 +41,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Ip __find_if_impl(_Ip __first, _Sp __last, _Pre

namespace __find_if {
struct __fn {
template <input_iterator _Ip,
sentinel_for<_Ip> _Sp,
template <input_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_unary_predicate<projected<_Ip, _Proj>> _Pred>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip
operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const {
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter
operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
return ranges::__find_if_impl(std::move(__first), std::move(__last), __pred, __proj);
}

Expand Down
10 changes: 5 additions & 5 deletions libcxx/include/__algorithm/ranges_find_if_not.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
namespace __find_if_not {
struct __fn {
template <input_iterator _Ip,
sentinel_for<_Ip> _Sp,
template <input_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_unary_predicate<projected<_Ip, _Proj>> _Pred>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip
operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const {
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter
operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
auto __pred2 = [&](auto&& __e) -> bool { return !std::invoke(__pred, std::forward<decltype(__e)>(__e)); };
return ranges::__find_if_impl(std::move(__first), std::move(__last), __pred2, __proj);
}
Expand Down
12 changes: 6 additions & 6 deletions libcxx/include/__algorithm/ranges_max_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
namespace __max_element {
struct __fn {
template <forward_iterator _Ip,
sentinel_for<_Ip> _Sp,
class _Proj = identity,
indirect_strict_weak_order<projected<_Ip, _Proj>> _Comp = ranges::less>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip
operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const {
template <forward_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); };
return ranges::__min_element_impl(__first, __last, __comp_lhs_rhs_swapped, __proj);
}
Expand Down
18 changes: 9 additions & 9 deletions libcxx/include/__algorithm/ranges_min_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {

// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`.
template <class _Ip, class _Sp, class _Proj, class _Comp>
_LIBCPP_HIDE_FROM_ABI constexpr _Ip __min_element_impl(_Ip __first, _Sp __last, _Comp& __comp, _Proj& __proj) {
template <class _Iter, class _Sent, class _Proj, class _Comp>
_LIBCPP_HIDE_FROM_ABI constexpr _Iter __min_element_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) {
if (__first == __last)
return __first;

_Ip __i = __first;
_Iter __i = __first;
while (++__i != __last)
if (std::invoke(__comp, std::invoke(__proj, *__i), std::invoke(__proj, *__first)))
__first = __i;
Expand All @@ -45,12 +45,12 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Ip __min_element_impl(_Ip __first, _Sp __last,

namespace __min_element {
struct __fn {
template <forward_iterator _Ip,
sentinel_for<_Ip> _Sp,
class _Proj = identity,
indirect_strict_weak_order<projected<_Ip, _Proj>> _Comp = ranges::less>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip
operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const {
template <forward_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
return ranges::__min_element_impl(__first, __last, __comp, __proj);
}

Expand Down
12 changes: 6 additions & 6 deletions libcxx/include/__algorithm/ranges_minmax_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ using minmax_element_result = min_max_result<_T1>;

namespace __minmax_element {
struct __fn {
template <forward_iterator _Ip,
sentinel_for<_Ip> _Sp,
class _Proj = identity,
indirect_strict_weak_order<projected<_Ip, _Proj>> _Comp = ranges::less>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_element_result<_Ip>
operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const {
template <forward_iterator _Iter,
sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_strict_weak_order<projected<_Iter, _Proj>> _Comp = ranges::less>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_element_result<_Iter>
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
auto __ret = std::__minmax_element_impl(std::move(__first), std::move(__last), __comp, __proj);
return {__ret.first, __ret.second};
}
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/__algorithm/ranges_transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _Ip, class _Op>
using unary_transform_result = in_out_result<_Ip, _Op>;
template <class _InIter, class _OutIter>
using unary_transform_result = in_out_result<_InIter, _OutIter>;

template <class _I1, class _I2, class _O1>
using binary_transform_result = in_in_out_result<_I1, _I2, _O1>;
template <class _InIter1, class _InIter2, class _OutIter>
using binary_transform_result = in_in_out_result<_InIter1, _InIter2, _OutIter>;

namespace __transform {
struct __fn {
Expand Down
Loading