Почему перегрузка r-значения `operator<<` для `basic_ostream` возвращает ссылку на l-значение?

§27.7.3.9 определяет следующую перегрузку для operator:

template 
  basic_ostream&
  operator<<(basic_ostream&& os, const T& x);

Действует: os
Возвращает: os

(§27.7.2.6 определяет перегрузку rvalue для operator>>)
. По сути, это просто переадресация к перегрузке lvalue. Я считаю эту перегрузку довольно опасной (istream даже более опасной, чем ostream), рассмотрим следующее:

#include 
#include 

int main(){
  auto& s = (std::stringstream() << "hi there!\n");
  std::cout << s.rdbuf(); // oops
}

Живой пример на Ideone (прекрасный пример неопределенного поведения. Ничего не печатает на MSVC10).

Приведенный выше пример может показаться надуманным, но попасть в такую ситуацию в общем коде или при передаче (std::stringstream() функции, которая предоставляет перегрузку lvalue и rvalue и сохраняет std::ostream или std::istream разными способами в зависимости от перегрузки, не должно быть слишком сложно.

Итак, какие аргументы против возврата basic_ostream&&& и указания следующего?

Returns: move(os)

(И то же самое для basic_istream.)

Есть ли что-то, что я упускаю из виду? В текущем состоянии, на мой взгляд, это выглядит просто опасно и похоже на дефект. Я бегло просмотрел список проблем LWG и нашел это предложение (привет @HowardHinnant!). Оно действительно возвращает r-значение, однако только для дополнительного преимущества возможности цепочки этого специального оператора, а не для решения проблемы безопасности, которую я описал выше (хотя оно, конечно, решает ее). Кроме того, он помечен как закрытый и для повторного рассмотрения в следующем стандарте. Поэтому я решил спросить здесь:

Есть ли какая-нибудь веская причина, по которой вышеупомянутая перегрузка возвращает ссылку на lvalue?

24
задан Xeo 12 January 2012 в 01:20
поделиться