2015-03-21 11 views
10

Considerate questo codice:Perché siamo autorizzati a prendere l'indirizzo di un tipo incompleto?

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 

Perché C++ permette di prendere l'indirizzo di un tipo di riferimento incompleto?

Potrebbe non essere potenzialmente illegale, come mostrato sopra? È intenzionale?

+4

Penso che la domanda migliore sia "perché C++ consente l'overloading di' & 'in primo luogo": D –

+0

Non avevo idea di poter sovraccaricare l'operatore '&()'. A volte penso che il C++ permetta agli sviluppatori di * troppo *. – tenfour

+0

@tenfour: posso letteralmente pensare a una sola situazione in cui è utile, e cioè quando * rappresenta * l'operazione -di operazione in notazione lambda, ad es. 'Foo [& _ 1]'. – Mehrdad

risposta

5

Sì, è intenzionale e la possibilità di rottura se operator& è sovraccaricata è nota.

Prendere l'indirizzo di tipi incompleti è stato possibile da molto prima del C++. In C, non c'è assolutamente alcun rischio di rottura, perché & non può essere sovraccaricato.

C++ ha scelto di non interrompere inutilmente i programmi precedentemente validi e ha semplicemente specificato che se un tipo incompleto risulta avere un operatore sovraccarico &, non è specificato se viene utilizzato l'operatore sovraccarico.

N4140 quotazioni:

5.3.1 operatori unari [expr.unary.op]

Se & viene applicato ad un lvalue di tipo classe incompleta e il tipo completo dichiara operator&(), essa non è specificato se l'operatore ha il significato incorporato o se viene richiamata la funzione dell'operatore.

Questo può essere interpretato da applicare anche a una classe in fase di dichiarata, e anche quando la dichiarazione di operator& è già stato visto:

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 
} 

Qui, GCC dà m tipo A * e respinge il programma , ma clang gli dà tipo int e lo accetta.

+0

+1 wow. L'ultima frase vale anche se '&' non è usato quando il tipo è incompleto? In altre parole, il compilatore può ignorare clamorosamente sovraccarico '&' sempre? – Mehrdad

+0

@ Mehrdad Non capisco cosa intendi con quel commento. Se il compilatore vede che il tipo è incompleto, i tentativi di cercare un operatore 'sovraccarico' falliranno, quindi è possibile trovare solo l'operatore integrato. Ma allo stesso tempo, un compilatore non è tenuto a tenere traccia di esattamente in quali punti del programma il tipo non è ancora completo, e se la compilazione non avviene rigorosamente dall'alto verso il basso, può vedere il tipo come completo (e trova l'operatore sovraccarico) anche quando non te lo aspetti. – hvd

+0

Sto solo dicendo che l'ultima frase non chiarisce quando esattamente il comportamento non è specificato: è sempre non specificato, o solo non specificato quando '&' non è ancora definito? – Mehrdad

Problemi correlati