10

Consider this code:

class Addressable;
class Class1  { void foo(Addressable &a) { (void) &a; } };  // OK
class Addressable { void *operator &() { return this; } };
class Class2  { void foo(Addressable &a) { (void) &a; } };  // Error: operator & private

Why does C++ allow taking the address of an incomplete reference type?

Couldn't it be potentially illegal, as shown above? Is this intentional?

user541686
  • 205,094
  • 128
  • 528
  • 886

1 Answers1

5

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.

Community
  • 1
  • 1
  • +1 wow. Does the last sentence hold even if `&` is not used when the type is incomplete? In other words, can the compiler blatantly ignore overloaded `&` all the time? – user541686 Mar 21 '15 at 09:17
  • @Mehrdad I don't understand what you mean by that comment. If the compiler sees that the type is incomplete, then attempts to look for an overloaded `operator&` will fail, so only the built-in operator can be found. But at the same time, a compiler is not required to keep track of at exactly which points in the program the type is not yet complete, and if compilation doesn't happen strictly from top to bottom, it may see the type as complete (and find the overloaded operator) even when you don't expect it. –  Mar 21 '15 at 09:20
  • I'm just saying that your last sentence doesn't make it clear when exactly the behavior is unspecified: is it always unspecified, or only unspecified when `&` is not yet defined? – user541686 Mar 21 '15 at 10:36
  • @Mehrdad Always. Edited my answer to give a concrete example. –  Mar 21 '15 at 11:35