This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


2567. Operator lookup ambiguity

Section: 6.5.2  [class.member.lookup]     Status: NAD     Submitter: Daveed Vandevoorde     Date: 2022-04-01

Consider:

  struct B1 {
    bool operator==(B1 const&) const;
  };
  struct B2 {
    bool operator==(B2 const&) const;
  };
  struct D: B1, B2 {} d;
  bool operator==(D const&, D const&);

  auto r = d == d; // ambiguous?

There is implementation divergence in handling this example; some implementations select the non-member operator, others diagnose an ambiguous lookup.

Member name lookup for operator== is ambiguous, making the program ill-formed per 6.5.2 [class.member.lookup] paragraph 6:

The result of the search is the declaration set of S(N, T). If it is an invalid set, the program is ill-formed.

There is no provision for simply failing if the lookup is invoked as part of some larger lookup, as in the case of a lookup for an overloaded operator (12.2.2.3 [over.match.oper] paragraph 3):

For a unary operator @ with an operand of type cv1 T1, and for a binary operator @ with a left operand of type cv1 T1 and a right operand of type cv2 T2, four sets of candidate functions, designated member candidates, non-member candidates, built-in candidates, and rewritten candidates, are constructed as follows:

It is unclear whether that is intended or desirable.

Suggested resolution:

Change in 6.5.2 [class.member.lookup] paragraph 6 as follows:

The result of the search is If the declaration set of S(N, T). If it is an invalid set, the program is ill-formed the result of the search is an empty set; otherwise, the result is that set.

Rationale (CWG 2023-06-17)

Changing the lookup rules to yield an empty set has undesirable effects on non-operator lookup, where fall-back to non-member lookup is actually desired. The intended outcome for the example is as specified (i.e. the program is ill-formed). The example can be addressed by making operator== a member of D.