Почему нам разрешено указывать адрес неполного типа?

Рассмотрим этот код:

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

Почему С++ разрешает использовать адрес неполного ссылочного типа?

Не может ли это быть незаконным, как показано выше? Это намеренно?

Ответ 1

Да, это преднамеренное и возможность поломки, если operator& перегружена, известно.

Возникновение адреса неполных типов возможно задолго до С++. В C нет абсолютно никакого риска поломки, потому что & не может быть перегружен.

С++ решила не излишне разорвать ранее действующие программы и просто указала, что если у неполного типа оказывается перегруженный оператор &, он не укажет, будет ли использоваться перегруженный оператор.

Цитата N4140:

5.3.1 Унарные операторы [expr.unary.op]

Если & применяется к lvalue неполного типа класса и полный тип объявляет operator&(), то не указано, вызывается ли оператор встроенным значением или вызывается функция оператора.

Это можно интерпретировать как применимое даже к объявляемому классу, и даже если объявление operator& уже было замечено:

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
}

Здесь GCC дает m тип A * и отклоняет программу, но clang дает ему тип int и принимает его.