diff --git a/libcxx/include/__ranges/to.h b/libcxx/include/__ranges/to.h index c937b0656de87..2ef6606595526 100644 --- a/libcxx/include/__ranges/to.h +++ b/libcxx/include/__ranges/to.h @@ -10,6 +10,7 @@ #ifndef _LIBCPP___RANGES_TO_H #define _LIBCPP___RANGES_TO_H +#include <__algorithm/ranges_for_each.h> #include <__concepts/constructible.h> #include <__concepts/convertible_to.h> #include <__concepts/derived_from.h> @@ -70,6 +71,20 @@ concept __constructible_from_iter_pair = derived_from>::iterator_category, input_iterator_tag> && constructible_from<_Container, iterator_t<_Range>, sentinel_t<_Range>, _Args...>; +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __container_append(_Container& __c) { + if constexpr (requires { __c.emplace_back(std::declval<_Ref>()); }) + return [&__c](_Ref&& __ref) { __c.emplace_back(std::forward<_Ref>(__ref)); }; + else if constexpr (requires { __c.push_back(std::declval<_Ref>()); }) + return [&__c](_Ref&& __ref) { __c.push_back(std::forward<_Ref>(__ref)); }; + else if constexpr (requires { __c.emplace(__c.end(), std::declval<_Ref>()); }) + return [&__c](_Ref&& __ref) { __c.emplace(__c.end(), std::forward<_Ref>(__ref)); }; + else { + static_assert(requires { __c.insert(__c.end(), std::declval<_Ref>()); }); + return [&__c](_Ref&& __ref) { __c.insert(__c.end(), std::forward<_Ref>(__ref)); }; + } +} + template concept __always_false = false; @@ -109,21 +124,8 @@ template __result.reserve(static_cast>(ranges::size(__range))); } - for (auto&& __ref : __range) { - using _Ref = decltype(__ref); - if constexpr (requires { __result.emplace_back(std::declval<_Ref>()); }) { - __result.emplace_back(std::forward<_Ref>(__ref)); - } else if constexpr (requires { __result.push_back(std::declval<_Ref>()); }) { - __result.push_back(std::forward<_Ref>(__ref)); - } else if constexpr (requires { __result.emplace(__result.end(), std::declval<_Ref>()); }) { - __result.emplace(__result.end(), std::forward<_Ref>(__ref)); - } else { - static_assert(requires { __result.insert(__result.end(), std::declval<_Ref>()); }); - __result.insert(__result.end(), std::forward<_Ref>(__ref)); - } - } + ranges::for_each(__range, ranges::__container_append>(__result)); return __result; - } else { static_assert(__always_false<_Container>, "ranges::to: unable to convert to the given container type."); } diff --git a/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp b/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp index a983745fd636e..26c7af6d88479 100644 --- a/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp +++ b/libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp @@ -550,11 +550,30 @@ constexpr void test_recursive() { assert(std::ranges::to(in_owning_view) == result); } +struct adl_only_range { + static constexpr int numbers[2]{42, 1729}; + + void begin() const = delete; + void end() const = delete; + + friend constexpr const int* begin(const adl_only_range&) { return std::ranges::begin(numbers); } + friend constexpr const int* end(const adl_only_range&) { return std::ranges::end(numbers); } +}; + +constexpr void test_lwg4016_regression() { + using Cont = Container; + + std::ranges::contiguous_range auto r = adl_only_range{}; + auto v = r | std::ranges::to(); + assert(std::ranges::equal(v, adl_only_range::numbers)); +} + constexpr bool test() { test_constraints(); test_ctr_choice_order(); test_lwg_3785(); test_recursive(); + test_lwg4016_regression(); return true; }