Skip to content

CWG3123 [stmt.expand] begin(E)/end(E) should perform overload resolution #803

Closed
cplusplus/draft
#8924

Description

@Sirraide

Full name of submitter (unless configured in github; will be published with the issue): Ambrose T.

Reference (section label): [stmt.expand]

Link to reflector thread (if any): N/A

Issue description:

[stmt.expand]p3 reads:

An expression is expansion-iterable, if [...]

  • argument-dependent lookups for begin(E) and for end(E) each find at least one function or function template.

This wording seems to imply that if any function or function template with the name begin/end (at least one each) is found via ADL, then E is expansion-iterable. This seems much too broad as it doesn’t take into consideration whether begin(E) or end(E) would even be well-formed.

E.g. if E is of type std::tuple<...>, then ADL for begin/end in namespace std will find quite a few functions (or function templates), but none of them accept a parameter of type std::tuple<...>, and the intent is surely that expansion over a std::tuple<...> be destructuring rather than iterating.

Suggested resolution:

Change the requirement from name lookup succeeding to overload resolution succeeding (notably, if overload resolution succeeds but there is no usable candidate, the program should be ill-formed).

Activity

  1. Sirraide commented on Nov 11, 2025

    @Sirraide
    Author
  2. t3nsor commented on Nov 11, 2025

    @t3nsor

    This is not the only example of core language rules that are based on a name being found rather than whether overload resolution succeeds. We also have them in e.g. [expr.await] and [dcl.struct.bind]. I think there must be a reason why CWG likes it this way, even though I don't know what it is.

  3. jensmaurer commented on Nov 11, 2025

    @jensmaurer
    Member

    We usually do that for member functions (I thought), so that we "lock in" to the begin/end interpretation even if, due to slight mishaps in the declaration, the eventual expression involving begin/end would fail to compile. This protects users against accidents.

  4. brevzin commented on Nov 14, 2025

    @brevzin

    Maybe something like:

    argument-dependent lookups for begin(E) and for end(E) each find at least one viable function or function template.

    Also we're not checking if E.begin() or E.end() are actually viable either, since that part just checks if they exist at all. So maybe something similar for the first bullet?

  5. jensmaurer commented on Nov 14, 2025

    @jensmaurer
    Member

    Also we're not checking if E.begin() or E.end() are actually viable either,

    That's generally intentional: If name lookup finds these, they better be "of the right signature" to detect user errors (e.g. missing const on the declaration) early instead of falling back to random other overloads.

  6. jensmaurer commented on Nov 17, 2025

    @jensmaurer
    Member
  7. changed the title [-][stmt.expand] `begin(E)`/`end(E)` should perform overload resolution[/-] [+]CWG3123 [stmt.expand] `begin(E)`/`end(E)` should perform overload resolution[/+] on Nov 17, 2025
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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions