9

ich eine reale Situation haben, die in dem folgenden Beispiel zusammengefasst werden können:Mehrdeutige Mehrfachvererbung von Template-Klassen

template< typename ListenerType > 
struct Notifier 
{ 
    void add_listener(ListenerType&){} 
}; 

struct TimeListener{ }; 
struct SpaceListener{ }; 

struct A : public Notifier<TimeListener> 
     , public Notifier<SpaceListener> 
{ 

}; 

struct B : TimeListener{ }; 

int main() 
{ 
    A a; 
    B b; 

    a.add_listener(b); // why is ambiguous? 

    return 0; 
} 

Warum ist dem Compiler nicht offensichtlich, dass B ist ein TimeListener und damit die einzig mögliche Überladungsauflösung ist Notifier<TimeListener>::add_listener(TimeListener&)?

+4

Sie Ihre Probleme lösen können mit 'mit Notifier :: add_listener; '(und der andere) in' struct A'. [Demo] (http://coliru.stacked-crooked.com/a/6e43848691a4cfcb) – Jarod42

Antwort

8

Die Suchregeln für Mitgliedsnamen sagen, dass der Code nicht eindeutig ist, weil die Der Name befindet sich in zwei Basisklassen und daher ist der Nachschlagesatz ungültig. Sie müssen nicht mit allen Details der Lookup-Sets und der Zusammenführung vertraut sein; Das wichtige Detail ist, dass beide Basisklassen überprüft werden und der Name add_listener in beiden gefunden wird, was eine Mehrdeutigkeit erzeugt.

Die einfache Lösung ist, diese Basisklassennamen in A mit using-Deklarationen zu bringen. Dies bedeutet, dass beide Versionen von add_listener in A nachgeschlagen, anstatt in den Basisklassen, so dass es keine merge Mehrdeutigkeit:

struct A : public Notifier<TimeListener> 
     , public Notifier<SpaceListener> 
{ 
    using Notifier<TimeListener>::add_listener; 
    using Notifier<SpaceListener>::add_listener; 
    //plus any more base classes 
}; 

Live Demo

5

Der angegebene Compiler ist nicht intelligent genug, um das Symbol aufzulösen - es ist als mehrdeutige Operation definiert, obwohl Sie es in diesem Fall logisch ausarbeiten könnten. Ihr Compiler sucht wahrscheinlich nur nach Symbolnamen und nicht nach Prototypen, nachdem er beide möglichen Symbole gefunden hat.

Sie können dem Compiler mitteilen, dass Sie beide Typen explizit akzeptieren, indem Sie die Vorlagensymbole, die Ihrer Meinung nach akzeptiert werden sollen, eindeutig disambiguieren. Dadurch wird der Compiler aufgefordert, entweder das Formular zu akzeptieren und dann die Vorlage anzuwenden. Unten ist ein Beispiel dafür. Das kann ich zur Zeit an meinem Computer nicht testen, aber es sollte funktionieren, wenn der Compiler Schwierigkeiten hat, die Symbole in Ihrem ursprünglichen Beispiel Lösung:

struct A : public Notifier<TimeListener> 
     , public Notifier<SpaceListener> 
{ 
    using Notifier<TimeListener>::add_listener; 
    using Notifier<SpaceListener>::add_listener; 
}; 
+6

Es ist nicht so, dass der Compiler nicht intelligent genug ist, der Standard sagt, dass dies nicht eindeutig ist. – TartanLlama

+0

Guter Punkt. Ich versuchte zu verdeutlichen, was ich mit "nicht intelligent genug" meinte, um die definierte Ambiguität einzukapseln. – Pyrce