2016-12-23 3 views
5

Warum gibt es keine Mehrdeutigkeit?Warum die const lvalue-Referenz Vorrang hat gegenüber der const rvalue-Referenz während der Überlastungsauflösung

struct B {}; 
struct C {}; 

struct A 
{ 
    A(B const &, C const &) {} 
    A(B const &&, C const &&) = delete; 
#if 0 
    A(B const &, C const &&) = delete; 
    A(B const &&, C const &) = delete; 
#endif 
}; 

B const b() { return {}; } // const result type may make sense 
C const c() { return {}; } // for some user-defined types 

int main() 
{ 
    A a0{B{}, C{}}; // I want to prohibit this 
    A a1{b(), c()}; // and this cases 
    B const bb{}; 
    C const cc{}; 
    A a2{b(), cc}; // But surely I also want to prohibit this 
    A a3{bb, c()}; // and this cases to compile 
} 

Hier möchte ich Lvalue const Verweise auf B und C Instanzen in die Instanz von A zu speichern. Natürlich möchte ich sicherstellen, dass die Lebensdauer der referenzierten Objekte die Lebensdauer der Instanz A überwindet.

Um dies ich nur = delete; Überlastungen für B const && zu erreichen und C const &&, die zusätzlich B && und C && entsprechend übereinstimmt.

Der obige Ansatz funktioniert perfekt für Conversion-Konstruktoren (d. H. Unäre). Aber es stellt sich heraus, dass für höhere Aritäten ich explizit alle kombinatorisch möglichen Kombinationen, die const rvalue Referenzversionen von Parametern von Interesse (d. H. #if 1) umfasst = delete;.

Dann denke ich: "Warum gibt es keine Zweideutigkeit?", - weil die Mehrdeutigkeit auch die Erstellung von falschem Code im obigen Fall verhindern sollte.

Also Frage ist: "Warum gibt es keine Mehrdeutigkeit für den Fall der Konstruktor Aufruf?".

+0

'B const &&' bindet nicht an einen Lvalue. Dieser Konstruktor ist überhaupt nicht für "a3" geeignet; ebenfalls 'a2'. –

+0

@ T.C. 'B const &' bindet an einen rvalue jeder Art. – Orient

+2

Ja, aber nicht umgekehrt. Das ist der springende Punkt. –

Antwort

5

tl; dr: Es war re-so entworfen.

Unter the original move proposal wäre Ihr Code mehrdeutig. Unter diesem Vorschlag könnte lvales an Rvalue-Referenzen binden, würde jedoch eine Lvalue-Referenz bevorzugen, wenn es in der Überladungsgruppe vorhanden war.

Ziemlich spät im Prozess, als mehr Menschen begannen, den Vorschlag zu verstehen, und wie Konzepte für C++ 11, the rules were changed so that lvalues could not bind to rvalue references noch in Betracht gezogen wurden.

Ich persönlich fühlte nicht, dass diese Änderung notwendig war, aber weit mehr Leute mochten die Änderung, als es nicht gemocht, und die grundlegende Funktionalität der Bewegungssemantik würde in beide Richtungen funktionieren. Das war also definitiv ein Kompromiss, der sich lohnt, im Gegensatz dazu, überhaupt keine Bewegungssemantik zu bekommen.

Mit der Änderung, die L-Werte können nicht auf rvalue Referenzen binden, ist A(B const &&, C const &&) nicht Teil der Überlast Auflösung eingestellt, wenn entweder Argument ein L-Wert ist. A(B const &, C const &) verbleibt jedoch in der Überladungsgruppe, wenn eines oder beide Argumente lvales sind.

+0

Wenn "const &&" in der Lage ist, alle die gleichen Wertekategorien wie "const &" zu binden, dann wird das Problem wohl aufhören zu existieren. Sicherlich sollte der Abgleich der entsprechenden Kategorien Priorität haben. – Orient

+0

@Orient: Sie haben Recht. Dies ist der ursprüngliche Zugvorschlag. N2812 hat das im Jahr 2009 geändert. Ich denke nicht, dass es machbar ist, diese Änderung jetzt umzukehren. –

+0

'const &&' wird selten verwendet (wie 'auto' Schlüsselwort zwischen 90 'und 10'). Wenn also die Bedeutung von "const &&" geändert würde, aber die Bedeutung von '&&' erhalten bleibt, dann passiert nichts (?)? Nur ein imaginärer Fall. – Orient

Verwandte Themen