Warum gibt diese Funktion bei rvalue-Argumenten eine lvalue-Referenz zurück?

Die folgende Definition einesmin function

template <typename T, typename U>
constexpr auto
min(T&& t, U&& u) -> decltype(t < u ? t : u)
{
    return t < u ? t : u;
}

hat ein Problem: Es scheint, dass es vollkommen legal ist, @ zu schreib

min(10, 20) = 0;

Dies wurde mit Clang 3.5 und g ++ 4.9 getestet.

Die Lösung ist unkompliziert, verwenden Sie einfachstd::forward, um die "Wertigkeit" der Argumente wiederherzustellen, d. h. den Hauptteil und das @ zu änderdecltype sage

t < u ? std::forward<T>(t) : std::forward<U>(u)

Allerdings bin ich ratlos zu erklärenWaru Die erste Definition erzeugt keinen Fehler.

Gegeben mein Verständnis von Weiterleitung und universellen Referenzen, sowohlt undueiten ihre Argumenttypen als @ int&& Wenn ganzzahlige Literale übergeben werden. Innerhalb des Körpers vonmin, die Argumente haben Namen, also sind sie lWerte. Jetzt diewirklich komplizierte Regeln für den bedingten Operator kommen ins Spiel, aber ichdenke die zugehörige Zeile ist:

Beide E2 [und] E3 sind Werte des gleichen Typs. In diesem Fall hat das Ergebnis den gleichen Typ und die gleiche Wertkategorie.

und daher der Rückgabetyp vonoperator?: sollte seinint&& sollte es auch nicht? Allerdings haben (soweit ich das beurteilen kann) sowohl Clang als auch g ++min(int&&, int&&) Rückgabe einer Wertreferenzint&, so dass ich das Ergebnis zuweisen kann.

Klar gibt es eine Lücke in meinem Verständnis, aber ich bin mir nicht sicher, was genau ich vermisse. Kann mir jemand genau erklären, was hier los ist?

BEARBEITEN

Wie Niall richtig hervorhebt, liegt das Problem hier nicht beim bedingten Operator (der einen Wert vom Typ @ zurückgibtint&& wie erwartet), aber mit demdecltype. Die Regeln fürdecltype sage

wenn die Wertkategorie des Ausdrucks lvalue ist, gibt der decltype T & @ a

so wird der Rückgabewert der Funktionint&& &, das nach den Kollapsregeln von C ++ 11 zu einfachem @ wiint& (entgegen meiner Erwartungint&&).

Aber wenn wir @ verwendstd::forward, drehen wir das zweite und dritte Argument vonoperator?: (zurück) in rvalues - speziell in xvalues. Da x-Werte immer noch gl-Werte sind (bleiben Sie hinten dran?), Gilt dieselbe bedingte Operatorregel, und wir erhalten ein Ergebnis desselben Typs und derselben Wertkategorie: einint&& das ist ein xwert.

Nun, wenn die Funktion zurückkehrt, wird ein anderes @ ausgelödecltype Regel:

wenn die Wertkategorie von expression xvalue ist, gibt der decltype T && @ a

Diesmal gibt uns die zusammenbrechende Referenzint&& && = int&& und, was noch wichtiger ist, die Funktion gibt einen x-Wert zurück. Dies macht es illegal, den Rückgabewert so zuzuweisen, wie wir es möchten.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage