Mehrdeutigkeit bei der Disambiguierung von Mehrfachvererbung
Beim Umgang mit Mehrfachvererbung mithilfe von Vorlagenbasisklassen entsteht ein potenzielles Problem hinsichtlich der Auflösung mehrdeutiger Mitgliedsfunktionen. Stellen Sie sich das folgende Szenario vor:
template
class Base {
public:
template
typename std::enable_if::value>::type foo() {
std::cout Hier ist die Funktion foo() nur aufrufbar, wenn der Vorlagenparameter mit einem der Typen im Types-Paket übereinstimmt. Wenn nun eine abgeleitete Klasse von mehreren Basisklassen mit nicht überlappenden Typsätzen erbt, kann der Compiler beim Auflösen des foo()-Aufrufs auf Mehrdeutigkeiten stoßen.
struct Derived: public Base,
public Base
{};
In diesem Fall würde der Aufruf Derived().foo() idealerweise die foo()-Memberfunktion von Base aufrufen. Allerdings melden sowohl GCC als auch Clang eine Mehrdeutigkeit.
Warum der Compiler die Mehrdeutigkeit nicht auflösen kann
Der Kompilierungsfehler entsteht aufgrund der Zusammenführungsregeln für die Suche nach Mitgliedsfunktionen. Gemäß dem C-Standard durchsucht der Suchprozess nacheinander die Basisklassen, wenn die Memberfunktion nicht in der abgeleiteten Klasse selbst deklariert ist. Wenn sich jedoch die Deklarationssätze in den Basisklassen unterscheiden, wird die Zusammenführung mehrdeutig.
Im gegebenen Szenario deklariert die abgeleitete Klasse Derived foo() nicht explizit, sodass der Compiler die Nachschlagesätze aus dem zusammenführen muss zwei Basisklassen. Da die Basisklassen unterschiedliche Deklarationssätze für foo() enthalten, führt die Zusammenführung zu Mehrdeutigkeiten.
Solutions
Um diese Mehrdeutigkeit aufzulösen, besteht eine Möglichkeit darin, using-Deklarationen zu verwenden in der abgeleiteten Klasse, um die gewünschten Mitgliedsfunktionen explizit zu importieren. Dies erfordert jedoch, dass der Benutzer diese Deklarationen hinzufügt, was bei großen Typlisten ausführlich und unpraktisch sein kann.
struct Derived: public Base,
public Base
{
using Base::foo;
using Base::foo;
};
Alternativ kann man eine Hilfsklasse verwenden, die die Mitgliedsfunktionen aller Basisklassen sammelt und zusammenführt, sodass die abgeleitete Klasse direkt darauf zugreifen kann.
template
struct BaseCollector : Bases...
{
using Bases::foo...;
};
struct Derived : BaseCollector , Base>
{};
Bei diesem Ansatz muss der Benutzer keine zusätzlichen Deklarationen hinzufügen, um die Mehrdeutigkeit aufzulösen. Die BaseCollector-Klasse führt effektiv die Deklarationssätze aller Basisklassen zusammen und macht die foo()-Funktion ohne Mehrdeutigkeit für die abgeleitete Klasse verfügbar.
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3