§27.7.3.9
определяет следующую перегрузку для operator<<
:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
Эффекты: os << x
Возвращает: os
(§27.7.2.6
определяет перегрузку rvalue для operator>>
.)
По сути, он просто переходит к перегрузке lvalue. Я считаю эту перегрузку довольно опасной (на самом деле istream
даже больше, чем ostream
), рассмотрим следующее:
#include <sstream>
#include <iostream>
int main(){
auto& s = (std::stringstream() << "hi there!\n");
std::cout << s.rdbuf(); // oops
}
Живой пример на Ideone (прекрасный пример неопределенного поведения. Ничего не печатает для меня на MSVC10).
Приведенный выше пример может показаться надуманным, но не должно быть слишком сложно попасть в эту ситуацию в общем коде или при передаче (std::stringstream() << "text")
в функцию, которая обеспечивает lvalue и перегрузку rvalue и сохраняет std::ostream
или std::istream
по-разному в зависимости от перегрузки.
Теперь, что будет аргументом, возвращающим basic_ostream<charT, traits>&&
и указывающим следующее?
Возвращает: move (os)
(И то же самое для basic_istream
.)
Есть что-нибудь, что я пропускаю? При нынешнем состоянии, на мой взгляд, это выглядит просто опасно и похоже на дефект. Я пролистал список LWG и нашел это предложение (привет @HowardHinnant!). Он действительно возвращает значение, однако только для дополнительной выгоды возможности связать этого специального оператора, не обращаясь конкретно к проблеме безопасности, которую я описал выше (хотя, безусловно, действительно решает ). Кроме того, он помечен как закрытый и для повторного рассмотрения для следующего стандарта. Поэтому я решил спросить здесь:
Есть ли веская причина, по которой вышеупомянутая перегрузка возвращает ссылку lvalue?