Skip to content

[libc++] <ranges>: ranges::to use range-based for loops in append branches #119133

@hewillk

Description

@hewillk
Contributor

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));
}
}

Range-based for loop is not guaranteed to be well-formed for input_range as it does not extract iterator-pair through ranges::begin/ranges::end:

https://godbolt.org/z/Kc3dsvnfW

#include <ranges>

struct Vector {
  void push_back(int);
};

struct OnlyADLRange {
  void begin() = delete;
  void end() = delete;
  friend int* begin(OnlyADLRange&);
  friend int* end(OnlyADLRange&);
};

int main() {
  std::ranges::contiguous_range auto r = OnlyADLRange{};
  auto v = r | std::ranges::to<Vector>(); // only well-formed in libstdc++
}

Activity

changed the title [-]`<ranges>`: `ranges::to` use range-based for loops in append branches[/-] [+][libc++] `<ranges>`: `ranges::to` use range-based for loops in append branches[/+] on Dec 8, 2024
added
libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
rangesIssues related to `<ranges>`
and removed on Dec 9, 2024
hewillk

hewillk commented on Dec 9, 2024

@hewillk
ContributorAuthor

range_formatter have similar issues:

for (auto&& __e : __range) {
if (__use_separator)
__ctx.advance_to(ranges::copy(__separator_, __ctx.out()).out);
else
__use_separator = true;

hewillk

hewillk commented on Dec 9, 2024

@hewillk
ContributorAuthor

It looks like libc++ extensively uses range-for loops to iterate over ranges when implementing P1206, so this should be something that can be modified uniformly (if worth it).

frederick-vs-ja

frederick-vs-ja commented on Dec 9, 2024

@frederick-vs-ja
Contributor

I think I can fix these issues (if wanted). But they mean that we can't traverse a range using range-for in generic code, which sounds weird.

philnik777

philnik777 commented on Dec 9, 2024

@philnik777
Contributor

Yeah, I think there should be an LWG or CWG issue about this. Not being able to iterate a range with a range-based for loop sounds a lot like a design flaw to me.

jwakely

jwakely commented on Sep 12, 2025

@jwakely
Contributor

I think we should change the std::range concept to say that it is not modelled by silly types where range-based for and ranges::for_each disagree. That means implementers don't need to bend over backwards to support such types, the types are just bad and should feel bad. Maybe your program will still "work" if you use such types where a range is required, for some value of "work", but formally it will be ill-formed; no diagnostic required.

jwakely

jwakely commented on Sep 12, 2025

@jwakely
Contributor

Most importantly, declaring such types bad means no changes needed to implementations. We can just keep doing what we do.

frederick-vs-ja

frederick-vs-ja commented on Sep 12, 2025

@frederick-vs-ja
Contributor

I think we should change the std::range concept to say that it is not modelled by silly types where range-based for and ranges::for_each disagree.

Looks weird but comprehensible to me. I thought that it was intended that the range concept should be stricter than range-for and these types shouldn't satisfy range. But then I sadly found that the intent might be somehow unachievable (or at least couldn't be reasonably achieved)...

hewillk

hewillk commented on Sep 13, 2025

@hewillk
ContributorAuthor

I think we should change the std::range concept to say that it is not modelled by silly types where range-based for and ranges::for_each disagree.

I'd actually love to see an LWG on this.
For example, add a semantic requirement for the range concept that ranges::for_each(rg, [](auto&& e){}) must be equivalent to for (auto&& e : rg).

jwakely

jwakely commented on Sep 17, 2025

@jwakely
Contributor

There are currently types that can't be used with range-based for at all, so in order to be able to use range-based for to iterate over a range we would need core language changes to allow for to work with all types that model range. Which could be difficult to get through the committee.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.rangesIssues related to `<ranges>`

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @jwakely@frederick-vs-ja@philnik777@hewillk

      Issue actions

        [libc++] `<ranges>`: `ranges::to` use range-based for loops in append branches · Issue #119133 · llvm/llvm-project