Skip to content

Commit 1728e0f

Browse files
[libc++][ranges] Fix ranges::to with ADL-only begin/end
When implementing the resolution of LWG4016, the `ranges::for_each` call to reduce inclusion dependency. However, the inlining was not always correct, because builtin-in range-`for` may just stop and fail when a deleted member `begin`/`end` function is encountered, while `ranges` CPOs continue to consider ADL-found `begin`/`end`. As a result, we should still use `ranges::begin`/`ranges::end`.
1 parent 170467e commit 1728e0f

File tree

2 files changed

+24
-2
lines changed
  • libcxx
    • include/__ranges
    • test/std/ranges/range.utility/range.utility.conv

2 files changed

+24
-2
lines changed

libcxx/include/__ranges/to.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,11 @@ template <class _Container, input_range _Range, class... _Args>
109109
__result.reserve(static_cast<range_size_t<_Container>>(ranges::size(__range)));
110110
}
111111

112-
for (auto&& __ref : __range) {
113-
using _Ref = decltype(__ref);
112+
auto __iter = ranges::begin(__range);
113+
auto __sent = ranges::end(__range);
114+
for (; __iter != __sent; ++__iter) {
115+
auto&& __ref = *__iter;
116+
using _Ref = decltype(__ref);
114117
if constexpr (requires { __result.emplace_back(std::declval<_Ref>()); }) {
115118
__result.emplace_back(std::forward<_Ref>(__ref));
116119
} else if constexpr (requires { __result.push_back(std::declval<_Ref>()); }) {

libcxx/test/std/ranges/range.utility/range.utility.conv/to.pass.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,30 @@ constexpr void test_recursive() {
550550
assert(std::ranges::to<C4>(in_owning_view) == result);
551551
}
552552

553+
struct adl_only_range {
554+
static constexpr int numbers[2]{42, 1729};
555+
556+
void begin() const = delete;
557+
void end() const = delete;
558+
559+
friend constexpr const int* begin(const adl_only_range&) { return std::ranges::begin(numbers); }
560+
friend constexpr const int* end(const adl_only_range&) { return std::ranges::end(numbers); }
561+
};
562+
563+
constexpr void test_lwg4016_regression() {
564+
using Cont = Container<int, CtrChoice::DefaultCtrAndInsert, InserterChoice::PushBack, true>;
565+
566+
std::ranges::contiguous_range auto r = adl_only_range{};
567+
auto v = r | std::ranges::to<Cont>();
568+
assert(std::ranges::equal(v, adl_only_range::numbers));
569+
}
570+
553571
constexpr bool test() {
554572
test_constraints();
555573
test_ctr_choice_order();
556574
test_lwg_3785();
557575
test_recursive();
576+
test_lwg4016_regression();
558577

559578
return true;
560579
}

0 commit comments

Comments
 (0)