This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
(From submission #362.)
Consider the following example, which is accepted by clang, but rejected by gcc:
#include <concepts> struct S1 { operator int*() { return nullptr; } }; struct S2 { template <class T> operator T() requires std::same_as<T, int*> { return nullptr; } }; int main() { S1 s1; S2 s2; return s1 - s2; }
The question is whether the implementation is required to find the built-in candidate std::ptrdiff_t operator-(int*, int*), and select that candidate. Subclause 12.5 [over.built] specifies an infinite number of built-in candidates, such as std::ptrdiff_t operator-(T*, T*) for every object type T. If there are infinitely many built-in candidates, the implementation cannot iterate through all of them to determine whether each candidate is viable.
The rule in 12.2.2.3 [over.match.oper] paragraph 3.3 is insufficient:
- ...
- ... For all other operators, the built-in candidates include all of the candidate operator functions defined in 12.5 [over.built] that, compared to the given operator,
- have the same operator name, and
- accept the same number of operands, and
- accept operand types to which the given operand or operands can be converted according to 12.2.4.2 [over.best.ics], and
- do not have the same parameter-type-list as any non-member candidate or rewritten non-member candidate that is not a function template specialization.
- ...
Suggested resolution:
Add a new paragraph before 12.5 [over.built] paragraph 3 as follows:
For the purposes of this subclause, a type T is admissible for an operand E if a standard conversion sequence (12.2.4.2.2 [over.ics.scs]) exists from E to T. If E has a class type, then T is also admissible for E if E's class has a non-template conversion function F (11.4.8.3 [class.conv.fct]) that would be viable (12.2.3 [over.match.viable]) for a call of the form (E).N(), where N is a hypothetical id-expression that names F, and a standard conversion sequence to T exists from the type specified by F. If E denotes an overload set (12.3 [over.over]), then T is admissible for E if E contains any non-template function for which T is admissible.
In the remainder of this subclause, vq represents either volatile or no cv-qualifier.
Change in 12.5 [over.built] paragraph 4 through 6 as follows:
For every pair (T , vq), where T is a cv-unqualified arithmetic type other than bool or a cv-unqualified pointer to (possibly cv-qualified) object type, there exist candidate operator functions of the form
vq T& operator++(vq T&); T operator++(vq T&, int); vq T& operator--(vq T&); T operator--(vq T&, int);if vq T& is admissible for the operand.For every (possibly cv-qualified) object type T and for every function type T that has neither cv-qualifiers nor a ref-qualifier, there exist candidate operator functions of the form
T& operator*(T *);if T* is admissible for the operand.For every type T such that T* is admissible for the operand, there exist candidate operator functions of the form
T* operator+(T *);
Change in 12.5 [over.built] paragraph 9 as follows:
For every quintuple (C1 , C2 , T , cv1, cv2 ), where C2 is a class type, C1 is the same type as C2 or is a derived class of C2 , and T is an object type or a function type, there exist candidate operator functions of the formcv12 T & operator->*(cv1 C1 *, cv2 T C2 ::*);where cv12 is the union of cv1 and cv2, if cv2 T C2::* is admissible for the second operand. The return type is shown for exposition only; see 7.6.4 [expr.mptr.oper] for the determination of the operator's result type.
Change in 12.5 [over.built] paragraph 13 through 16 as follows:
For every cv-qualified or cv-unqualified object type T there exist candidate operator functions of the form
T* operator+(T *, std::ptrdiff_t); T& operator[](T *, std::ptrdiff_t); T* operator-(T *, std::ptrdiff_t);if T is admissible for the first operand.For every cv-qualified or cv-unqualified object type T there exist candidate operator functions of the form
T* operator+(std::ptrdiff_t, T *); T& operator[](std::ptrdiff_t, T *);if T is admissible for the second operand.For every T , where T is a pointer to object type and is admissible for the left or right operand, there exist candidate operator functions of the form
std::ptrdiff_t operator-(T , T );For every T, where T is an enumeration type, or a pointer type that is admissible for the left or right operand, there exist candidate operator functions of the form
bool operator==(T , T ); bool operator!=(T , T ); bool operator<(T , T); bool operator>(T , T ); bool operator<=(T , T ); bool operator>=(T , T ); R operator<=>(T , T );where R is the result type specified in 7.6.8 [expr.spaceship].For every T, where T is a pointer-to-member type and is admissible for the left or right operand, or T is std::nullptr_t, there exist candidate operator functions of the form
bool operator==(T, T ); bool operator!=(T , T );
Change in 12.5 [over.built] paragraph 19 through 21 as follows:
For every pair (T , vq), where T is any type, there exist candidate operator functions of the form
T *vq & operator=(T *vq &, T *);if T vq& is admissible for the left operand or T* is admissible for the right operand.For every pair (T , vq), where T is an enumeration type, or T is a pointer-to-member type such that vq T& is admissible for the left operand or T is admissible for the right operand, there exist candidate operator functions of the form
vq T & operator=(vq T &, T );For every pair (T , vq), where T is a cv-qualified or cv-unqualified object type, there exist candidate operator functions of the form
T *vq & operator+=(T *vq &, std::ptrdiff_t); T *vq & operator-=(T *vq &, std::ptrdiff_t);if T*vq& is admissible for the left operand.
Change in 12.5 [over.built] paragraph 25 as follows:
For every type T, whereT is a pointer, pointer-to-member, or scoped enumeration type,there exist candidate operator functions of the form
- T is admissible for the second or third operand and is a pointer or pointer-to-member type, or
- T is a scoped enumeration type,
operator?:(bool, T, T);