This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116c. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-03-27
[Accepted as a DR at the March, 2024 meeting.]
Consider:
struct Base {
protected:
bool operator==(const Base& other) const = default;
};
struct Child : Base {
int i;
bool operator==(const Child& other) const = default;
};
bool b = Child() == Child(); //error: deleted operator==
Per 11.10.1 [class.compare.default] paragraph 6,
Let xi be an lvalue denoting the i-th element in the expanded list of subobjects for an object x (of length n), where xi is formed by a sequence of derived-to-base conversions (12.2.4.2 [over.best.ics]), class member access expressions (7.6.1.5 [expr.ref]), and array subscript expressions (7.6.1.2 [expr.sub]) applied to x.
The derived-to-base conversion for this loses the context of access to the protected Base::operator==, violating 11.8.5 [class.protected] paragraph 1. The example is rejected by implementations, but ought to work.
For this related example, there is implementation divergence:
struct B { protected: constexpr operator int() const { return 0; } }; struct D : B { constexpr bool operator==(const D&) const = default; }; template<typename T> constexpr auto comparable(T t) -> decltype(t == t) { return t == t; } constexpr bool comparable(...) { return false; } static_assert(comparable(D{}));
Is D::operator== deleted, because its defaulted definition violates the protected access rules? Is D::operator== not deleted, but synthesis fails on use because of the proctected access rules? Is the synthesis not in the immediate context, making the expression comparable(D{}) ill-formed?
CWG 2023-06-17
There is no implementation divergence; the first example yields a deleted operator== in the derived class.
Proposed resolution (approved by CWG 2023-12-01):
Change in 11.10.1 [class.compare.default] paragraph 1 as follows:
... Name lookups and access checks in the implicit definition (9.6.2 [dcl.fct.def.default]) of a comparison operator function are performed from a context equivalent to its function-body . A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function.
Additional notes (March, 2025)
Despite the intent, the applied resolution does not make the original example well-formed, because the object expression in the synthesized body of Child::operator== is of type Base, violating 11.8.5 [class.protected] paragraph 1. See issue 3007 for the next attempt.