Index: include/numeric =================================================================== --- include/numeric +++ include/numeric @@ -51,7 +51,7 @@ T transform_reduce(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init); // C++17 - + template T transform_reduce(InputIterator1 first1, InputIterator1 last1, @@ -75,10 +75,10 @@ OutputIterator exclusive_scan(InputIterator first, InputIterator last, OutputIterator result, T init); // C++17 - + template OutputIterator - exclusive_scan(InputIterator first, InputIterator last, + exclusive_scan(InputIterator first, InputIterator last, OutputIterator result, T init, BinaryOperation binary_op); // C++17 template @@ -108,7 +108,7 @@ transform_inclusive_scan(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op, UnaryOperation unary_op); // C++17 - + template OutputIterator @@ -196,7 +196,7 @@ typename iterator_traits<_InputIterator>::value_type reduce(_InputIterator __first, _InputIterator __last) { - return _VSTD::reduce(__first, __last, + return _VSTD::reduce(__first, __last, typename iterator_traits<_InputIterator>::value_type{}); } #endif @@ -226,7 +226,7 @@ template inline _LIBCPP_INLINE_VISIBILITY _Tp -transform_reduce(_InputIterator __first, _InputIterator __last, +transform_reduce(_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOp __b, _UnaryOp __u) { for (; __first != __last; ++__first) @@ -234,7 +234,7 @@ return __init; } -template inline _LIBCPP_INLINE_VISIBILITY _Tp @@ -249,10 +249,10 @@ template inline _LIBCPP_INLINE_VISIBILITY _Tp -transform_reduce(_InputIterator1 __first1, _InputIterator1 __last1, +transform_reduce(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _Tp __init) { - return _VSTD::transform_reduce(__first1, __last1, __first2, __init, + return _VSTD::transform_reduce(__first1, __last1, __first2, _VSTD::move(__init), _VSTD::plus<>(), _VSTD::multiplies<>()); } #endif @@ -298,7 +298,7 @@ template inline _LIBCPP_INLINE_VISIBILITY _OutputIterator -exclusive_scan(_InputIterator __first, _InputIterator __last, +exclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Tp __init, _BinaryOp __b) { if (__first != __last) @@ -318,14 +318,14 @@ template inline _LIBCPP_INLINE_VISIBILITY _OutputIterator -exclusive_scan(_InputIterator __first, _InputIterator __last, +exclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Tp __init) { return _VSTD::exclusive_scan(__first, __last, __result, __init, _VSTD::plus<>()); } template -_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, +_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOp __b, _Tp __init) { for (; __first != __last; ++__first, (void) ++__result) { @@ -336,7 +336,7 @@ } template -_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, +_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOp __b) { if (__first != __last) { @@ -350,17 +350,17 @@ } template -_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, +_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { return _VSTD::inclusive_scan(__first, __last, __result, std::plus<>()); } -template inline _LIBCPP_INLINE_VISIBILITY _OutputIterator -transform_exclusive_scan(_InputIterator __first, _InputIterator __last, +transform_exclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Tp __init, _BinaryOp __b, _UnaryOp __u) { @@ -379,7 +379,7 @@ } template -_OutputIterator transform_inclusive_scan(_InputIterator __first, _InputIterator __last, +_OutputIterator transform_inclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOp __b, _UnaryOp __u, _Tp __init) { for (; __first != __last; ++__first, (void) ++__result) { @@ -391,7 +391,7 @@ } template -_OutputIterator transform_inclusive_scan(_InputIterator __first, _InputIterator __last, +_OutputIterator transform_inclusive_scan(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryOp __b, _UnaryOp __u) { if (__first != __last) { @@ -400,7 +400,7 @@ if (++__first != __last) return _VSTD::transform_inclusive_scan(__first, __last, __result, __b, __u, __init); } - + return __result; } #endif Index: test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_init_bop_uop.pass.cpp =================================================================== --- test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_init_bop_uop.pass.cpp +++ test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_init_bop_uop.pass.cpp @@ -18,40 +18,26 @@ #include #include +#include +#include +#include "MoveOnly.h" #include "test_iterators.h" -template -struct identity : std::unary_function -{ - constexpr const T& operator()(const T& x) const { return x;} -}; - -template <> -struct identity +struct identity { template - constexpr auto operator()(T&& x) const - _NOEXCEPT_(noexcept(_VSTD::forward(x))) - -> decltype (_VSTD::forward(x)) - { return _VSTD::forward(x); } + constexpr decltype(auto) operator()(T&& x) const { + return std::forward(x); + } }; - -template struct twice -{ - constexpr const T operator()(const T& x) const noexcept { return 2 * x; } -}; - -template <> -struct twice { template - constexpr auto operator()(const T& x) const - _NOEXCEPT_(noexcept(2 * x)) - -> decltype (2 * x) - { return 2 * x; } + constexpr auto operator()(const T& x) const { + return 2 * x; + } }; template @@ -70,23 +56,23 @@ int ia[] = {1, 2, 3, 4, 5, 6}; unsigned sa = sizeof(ia) / sizeof(ia[0]); - test(Iter(ia), Iter(ia), 0, std::plus<>(), identity<>(), 0); - test(Iter(ia), Iter(ia), 1, std::multiplies<>(), identity<>(), 1); - test(Iter(ia), Iter(ia+1), 0, std::multiplies<>(), identity<>(), 0); - test(Iter(ia), Iter(ia+1), 2, std::plus<>(), identity<>(), 3); - test(Iter(ia), Iter(ia+2), 0, std::plus<>(), identity<>(), 3); - test(Iter(ia), Iter(ia+2), 3, std::multiplies<>(), identity<>(), 6); - test(Iter(ia), Iter(ia+sa), 4, std::multiplies<>(), identity<>(), 2880); - test(Iter(ia), Iter(ia+sa), 4, std::plus<>(), identity<>(), 25); - - test(Iter(ia), Iter(ia), 0, std::plus<>(), twice<>(), 0); - test(Iter(ia), Iter(ia), 1, std::multiplies<>(), twice<>(), 1); - test(Iter(ia), Iter(ia+1), 0, std::multiplies<>(), twice<>(), 0); - test(Iter(ia), Iter(ia+1), 2, std::plus<>(), twice<>(), 4); - test(Iter(ia), Iter(ia+2), 0, std::plus<>(), twice<>(), 6); - test(Iter(ia), Iter(ia+2), 3, std::multiplies<>(), twice<>(), 24); - test(Iter(ia), Iter(ia+sa), 4, std::multiplies<>(), twice<>(), 184320); // 64 * 2880 - test(Iter(ia), Iter(ia+sa), 4, std::plus<>(), twice<>(), 46); + test(Iter(ia), Iter(ia), 0, std::plus<>(), identity(), 0); + test(Iter(ia), Iter(ia), 1, std::multiplies<>(), identity(), 1); + test(Iter(ia), Iter(ia+1), 0, std::multiplies<>(), identity(), 0); + test(Iter(ia), Iter(ia+1), 2, std::plus<>(), identity(), 3); + test(Iter(ia), Iter(ia+2), 0, std::plus<>(), identity(), 3); + test(Iter(ia), Iter(ia+2), 3, std::multiplies<>(), identity(), 6); + test(Iter(ia), Iter(ia+sa), 4, std::multiplies<>(), identity(), 2880); + test(Iter(ia), Iter(ia+sa), 4, std::plus<>(), identity(), 25); + + test(Iter(ia), Iter(ia), 0, std::plus<>(), twice(), 0); + test(Iter(ia), Iter(ia), 1, std::multiplies<>(), twice(), 1); + test(Iter(ia), Iter(ia+1), 0, std::multiplies<>(), twice(), 0); + test(Iter(ia), Iter(ia+1), 2, std::plus<>(), twice(), 4); + test(Iter(ia), Iter(ia+2), 0, std::plus<>(), twice(), 6); + test(Iter(ia), Iter(ia+2), 3, std::multiplies<>(), twice(), 24); + test(Iter(ia), Iter(ia+sa), 4, std::multiplies<>(), twice(), 184320); // 64 * 2880 + test(Iter(ia), Iter(ia+sa), 4, std::plus<>(), twice(), 46); } template @@ -94,7 +80,16 @@ { T *p = nullptr; static_assert( std::is_same_v(), identity<>()))> ); + decltype(std::transform_reduce(p, p, Init{}, std::plus<>(), identity()))> ); +} + +void test_move_only_types() +{ + MoveOnly ia[] = {{1}, {2}, {3}}; + assert(60 == + std::transform_reduce(std::begin(ia), std::end(ia), MoveOnly{0}, + [](const MoveOnly& lhs, const MoveOnly& rhs) { return MoveOnly{lhs.get() + rhs.get()}; }, + [](const MoveOnly& target) { return MoveOnly{target.get() * 10}; }).get()); } int main() @@ -118,7 +113,9 @@ // Make sure the math is done using the correct type { auto v = {1, 2, 3, 4, 5, 6}; - unsigned res = std::transform_reduce(v.begin(), v.end(), 1U, std::multiplies<>(), twice<>()); + unsigned res = std::transform_reduce(v.begin(), v.end(), 1U, std::multiplies<>(), twice()); assert(res == 46080); // 6! * 64 will not fit into a char } + + test_move_only_types(); } Index: test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_iter_init.pass.cpp =================================================================== --- test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_iter_init.pass.cpp +++ test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_iter_init.pass.cpp @@ -17,7 +17,9 @@ #include #include +#include +#include "MoveOnly.h" #include "test_iterators.h" template @@ -56,6 +58,14 @@ decltype(std::transform_reduce(p, p, p, Init{}))> ); } +void test_move_only_types() +{ + MoveOnly ia[] = {{1}, {2}, {3}}; + MoveOnly ib[] = {{1}, {2}, {3}}; + assert(14 == + std::transform_reduce(std::begin(ia), std::end(ia), std::begin(ib), MoveOnly{0}).get()); +} + int main() { test_return_type(); @@ -92,4 +102,6 @@ test(); test< int*, const unsigned int *>(); test< int*, unsigned int *>(); + + test_move_only_types(); } Index: test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_iter_init_op_op.pass.cpp =================================================================== --- test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_iter_init_op_op.pass.cpp +++ test/std/numerics/numeric.ops/transform.reduce/transform_reduce_iter_iter_iter_init_op_op.pass.cpp @@ -19,7 +19,9 @@ #include #include +#include +#include "MoveOnly.h" #include "test_iterators.h" template @@ -58,6 +60,16 @@ decltype(std::transform_reduce(p, p, p, Init{}, std::plus<>(), std::multiplies<>()))> ); } +void test_move_only_types() +{ + MoveOnly ia[] = {{1}, {2}, {3}}; + MoveOnly ib[] = {{1}, {2}, {3}}; + assert(14 == + std::transform_reduce(std::begin(ia), std::end(ia), std::begin(ib), MoveOnly{0}, + [](const MoveOnly& lhs, const MoveOnly& rhs) { return MoveOnly{lhs.get() + rhs.get()}; }, + [](const MoveOnly& lhs, const MoveOnly& rhs) { return MoveOnly{lhs.get() * rhs.get()}; }).get()); +} + int main() { test_return_type(); @@ -94,4 +106,6 @@ test(); test< int*, const unsigned int *>(); test< int*, unsigned int *>(); + + test_move_only_types(); } Index: test/support/MoveOnly.h =================================================================== --- test/support/MoveOnly.h +++ test/support/MoveOnly.h @@ -19,7 +19,6 @@ class MoveOnly { - friend class MoveOnly2; MoveOnly(const MoveOnly&); MoveOnly& operator=(const MoveOnly&); @@ -35,6 +34,8 @@ bool operator==(const MoveOnly& x) const {return data_ == x.data_;} bool operator< (const MoveOnly& x) const {return data_ < x.data_;} + MoveOnly operator+(const MoveOnly& x) const { return MoveOnly{data_ + x.data_}; } + MoveOnly operator*(const MoveOnly& x) const { return MoveOnly{data_ * x.data_}; } }; namespace std {