Yes, that's intentional, and the possibility of breakage if operator&
is overloaded is known.
Taking the address of incomplete types has been possible since long before C++. In C, there is absolutely no risk of any breakage, because &
cannot be overloaded.
C++ chose not to unnecessarily break previously valid programs, and simply specified that if an incomplete type does turn out to have an overloaded &
operator, it's unspecified whether the overloaded operator gets used.
Quoting N4140:
5.3.1 Unary operators [expr.unary.op]
If &
is applied to an lvalue of incomplete class type and the complete type declares operator&()
, it is unspecified whether the operator has the built-in meaning or the operator function is called.
This can be interpreted to apply even to a class currently being declared, and even when a declaration of operator&
has already been seen:
extern struct A a;
struct A {
int operator&();
decltype(&a) m; // int, or A *?
};
int main() {
return A().m; // only valid if m is int
}
Here, GCC gives m
type A *
and rejects the program, but clang gives it type int
and accepts it.