Soweit ich C++ 11 Referenzen verstehe, sollte ich nicht in der Lage sein, eine Rvalue-Referenz an eine (nicht konstante) Lvalue-Referenz zu binden, da die erstere an eine temporäre gebunden werden könnte und die letztere nie an eine gebunden werden soll vorübergehend.Warum kann ich std :: einen Stream rvalue ref in einen lvalue ref verschieben?
Jedoch fand ich dieses seltsame Verhalten in Verbindung temporäre Stromobjekte
struct Dummy {};
template <typename Stream>
Stream& operator<<(Stream& s, Dummy) {
return s << "."; // <- (A)
}
template <typename Stream>
void pass(Stream&& s) {
std::move(s) << Dummy(); // <- (X) rvalue->lvalue conversion?
}
#include <fstream>
int main() {
pass(std::fstream("test",std::ios::out));
}
Wenn ich schreibe s << Dummy()
in Zeile (X)
, C++ klagt in Linie (A)
, sagen
error: invalid initialization of reference of type ‘std::basic_fstream<char>&’ from expression of type ‘std::basic_ostream<char>’
Doch warum tut der Code (wie oben gezeigt) kompiliert und funktioniert wie erwartet? Die von std::move
zurückgegebene rvalue-Referenz sollte genauso wenig an eine lvalue-Referenz gebunden sein wie der Ausdruck s
, aber sowohl gcc 4.6.1
als auch gcc 4.7.2
reagieren identisch.
Und warum scheint dieses Phänomen nur mit Streams zu funktionieren? Beim direkten Übergeben eines Dummy&&
an eine Funktion, erwartet ein T&
schlägt sowohl mit als auch ohne std::move
.
Ich sehe. Das macht Sinn. Aber warum ist 'std :: move 'überhaupt nötig? – bitmask
@bitmask: Weil ohne '' '' nicht an eine rvalue-Referenz gebunden werden kann, da es sich um einen lvalue handelt. –
@KerrekSB: Aber es hat eine vollkommen gute Überladung für einen rvalue referenzierten Stream, an den man sich binden kann (wie in dieser Antwort gezeigt). Warum passt diese Überladung nicht ohne Unterstützung von 'std :: move'? – bitmask