Warum sind meine T & T & Copy-Konstruktoren mehrdeutig?

8
%Vor%

Fehlermeldung:

%Vor%     
yuan 08.06.2013, 11:25
quelle

1 Antwort

9

Also, was passiert (oder vielmehr sollte passieren): Um diesen Konstruktor aufzulösen,

%Vor%

Der Compiler muss eine Überladungsauflösung durchführen und zuerst entscheiden, welche Konstruktoren brauchbare Kandidaten sind.

Als erstes müssen Sie beachten, dass beide Konstruktoren brauchbar sind: Formen wie T&& do nicht werden immer in rvalue-Referenzen aufgelöst (das ist nur der Fall, wenn das, was Sie übergeben, ein rvalue ist). Das nennt Scott Meyers "universal references " (beachte, dass dieser Begriff kein Standard ist).

Wenn der Compiler versucht, eine Typableitung durchzuführen, um festzustellen, ob der zweite Konstruktor realisierbar ist, wird der Typ T in diesem Fall zu Myclass& abgeleitet - da das, was Sie übergeben ( a ), ein lvalue ist ; und wegen der kollabierenden Referenzregeln gibt Myclass& && Myclass& an, so dass Sie die gleiche Signatur wie der erste Konstruktor haben.

So ist der Anruf mehrdeutig? Wie schon von Marc Glisse in den Kommentaren zu die Frage und durch Jonathan Wakely in den Kommentaren zu dieser Antwort , nein , sollte es nicht sein (wie die ursprüngliche Version dieser Antwort behauptet - mea culpa).

Der Grund ist, dass eine spezielle Regel im Standard angibt, dass die Überladung, die eine lvalue-Referenz annimmt, spezialisierter ist als die Überladung, die eine rvalue-Referenz akzeptiert. Gemäß Paragraph 14.8.2.4/9 des C ++ 11 Standards:

  

Wenn die Deduktion für einen gegebenen Typ in beide Richtungen erfolgreich ist (d. h. die Typen sind nach den Transformationen identisch)   oben) und sowohl P als auch A waren Referenztypen (bevor sie durch den Typ ersetzt wurden, auf den verwiesen wird)   oben):

     

- , wenn der Typ aus der Argumentvorlage eine lvalue-Referenz und der Typ aus dem Parameter war   Vorlage war nicht, der Argumenttyp wird als spezialisierter als der andere angesehen ; sonst, [...]

Dies bedeutet, dass der Compiler einen Fehler hat ( der Link zum Fehlerbericht wurde bereitgestellt) von Marc Glisse in den Kommentaren zu der Frage).

Um diesen Fehler zu umgehen, stellen Sie sicher, dass Ihre Konstruktorvorlage, die ein T&& akzeptiert, nur dann von GCC ausgewählt wird, wenn rvalues ​​übergeben wird. Sie können das folgendermaßen umschreiben:

%Vor%

Wo ich eine SFINAE-Einschränkung hinzugefügt habe, die den Compiler dazu veranlasst, diesen Konstruktor aus der Überladungsmenge zu verwerfen, wenn ein Lvalue übergeben wird.

Wenn ein Lvalue übergeben wird, wird T tatsächlich zu X& für einige X (der Typ des übergebenen Ausdrucks, Myclass in Ihrem Fall) und T&& abgeleitet Auflösen in X& ; Wenn ein rvalue übergeben wird, wird andererseits T zu X von einigen X (der Typ des übergebenen Ausdrucks, Myclass in deinem Fall) und T&& abgeleitet Auflösen in X&& .

Da die SFINAE-Einschränkung prüft, ob T nicht zu einem Referenztyp wird und andernfalls einen Substitutionsfehler erzeugt, wird Ihr Konstruktor garantiert nur dann berücksichtigt, wenn das Argument ein rvalue-Ausdruck ist.

Also, um alles zusammenzufassen:

%Vor%

Hier ist ein Live-Beispiel .

    
Andy Prowl 08.06.2013, 11:28
quelle

Tags und Links