std :: ostringstream печатает адрес c-строки вместо своего содержимого

Я наткнулся на странное поведение, которое я просто не мог объяснить сначала (см. Идеон ):

#include  #include  #include  int main() { std::cout << "Reference : " << (void const*)"some data" << "\n"; std::ostringstream s; s << "some data"; std::cout << "Regular Syntax: " << s.str() << "\n"; std::ostringstream s2; std::cout << "Semi inline : " << static_cast(s2 << "some data").str() << "\n"; std::cout << "Inline : " << dynamic_cast( std::ostringstream() << "some data" ).str() << "\n"; } 

Выдает вывод:

 Reference : 0x804a03d Regular Syntax: some data Semi inline : some data Inline : 0x804a03d 

Удивительно, но в последнем листе у нас есть адрес, а не контент!

Почему это так ?

Выражение std::ostringstream() создает временное выражение, а operator<< который принимает const char* поскольку аргумент является свободной функцией, но эта свободная функция не может быть вызвана временным образом, так как тип первого параметра функции std::ostream& которые не могут быть привязаны к временному объекту.

Сказав, что < разрешает вызов функции-члена, которая перегружена для void* которая печатает адрес. Обратите внимание, что функция-член может быть вызвана во временное.

Чтобы вызвать свободную функцию, вам нужно преобразовать временную (которая является rvalue) в lvalue, и вот один трюк, который вы можете сделать:

  std::cout << "Inline : " << dynamic_cast( std::ostringstream().flush() << "some data" ).str() << "\n"; 

То есть, std::ostringstream().flush() возвращает std::ostream& что означает, теперь можно std::ostream& свободную функцию, передав возвращаемую ссылку в качестве первого аргумента.

Кроме того, здесь вам не нужно использовать dynamic_cast (что происходит медленно, как это делается во время выполнения), поскольку тип объекта довольно известен, поэтому вы можете использовать static_cast (что быстро, как это делается на время компиляции):

  std::cout << "Inline : " << static_cast( std::ostringstream().flush() << "some data" ).str() << "\n"; 

который должен работать нормально.

Временное не может привязываться к ссылке на неконстантный формальный аргумент.

Поэтому не-член << не подбирается.

Вместо этого вы получаете версию void* .

C ++ 11 исправляет это, добавляя функцию вставки члена non-member rvalue ,

C ++ 11
§27.7.3.9 Вставка streamа Rvalue
[Ostream.rvalue]
template
basic_ostream&
operator<<(basic_ostream&& os, const T& x);

1 Эффекты: os << x
2 Возврат: os

Приветствия.

Чтобы начать работу, самым простым решением является получение списка возможных перегрузок, рассматриваемых компилятором, например, попытка :

 X x; std::cout << x << "\n"; 

где X - тип без какой-либо перегрузки для streamовой передачи, что дает следующий список возможных перегрузок:

 prog.cpp: In function 'int main()': prog.cpp:21: error: no match for 'operator<<' in 'std::cout << x' include/ostream:112: note: candidates are: std::ostream& std::ostream::operator<<(std::ostream& (*)(std::ostream&)) include/ostream:121: note: std::ostream& std::ostream::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) include/ostream:131: note: std::ostream& std::ostream::operator<<(std::ios_base& (*)(std::ios_base&)) include/ostream:169: note: std::ostream& std::ostream::operator<<(long int) include/ostream:173: note: std::ostream& std::ostream::operator<<(long unsigned int) include/ostream:177: note: std::ostream& std::ostream::operator<<(bool) include/bits/ostream.tcc:97: note: std::ostream& std::ostream::operator<<(short int) include/ostream:184: note: std::ostream& std::ostream::operator<<(short unsigned int) include/bits/ostream.tcc:111: note: std::ostream& std::ostream::operator<<(int) include/ostream:195: note: std::ostream& std::ostream::operator<<(unsigned int) include/ostream:204: note: std::ostream& std::ostream::operator<<(long long int) include/ostream:208: note: std::ostream& std::ostream::operator<<(long long unsigned int) include/ostream:213: note: std::ostream& std::ostream::operator<<(double) include/ostream:217: note: std::ostream& std::ostream::operator<<(float) include/ostream:225: note: std::ostream& std::ostream::operator<<(long double) include/ostream:229: note: std::ostream& std::ostream::operator<<(const void*) include/bits/ostream.tcc:125: note: std::ostream& std::ostream::operator<<(std::basic_streambuf<_CharT, _Traits>*) 

Сначала сканируем этот список, отметим, что char const* явно отсутствует, и поэтому логично, что вместо него будет выбран void const* и, следовательно, адрес будет напечатан.

На первый взгляд, мы отмечаем, что все перегрузки являются методами , и что здесь не существует ни одной свободной функции.

Проблема связана с привязкой ссылок: поскольку временное не может привязываться к ссылке на неконстантную, перегрузки формы std::ostream& operator<<(std::ostream&,X) отклоняются напрямую и остаются только функции-члены.

Это, насколько мне известно, ошибка проектирования на C ++, ведь мы выполняем мутирующую функцию-член во временном режиме, и для этого требуется (скрытая) ссылка на объект: x

Обходной путь, как только вы поняли, что пошло не так, относительно прост и требует только небольшой обертки:

 struct Streamliner { template  Streamliner& operator<<(T const& t) { _stream << t; return *this; } std::string str() const { return _stream.str(); } std::ostringstream _stream; }; std::cout << "Inline, take 2: " << (Streamliner() << "some data").str() << "\n"; 

Что печатает ожидаемый результат.

  • Есть ли стандартный class даты / времени в C ++?
  • Чтение больших текстовых файлов с streamами в C #
  • HttpWebRequest & Native GZip Compression
  • Можете ли вы объяснить концепцию streamов?
  • Как преобразовать struct System.Byte byte в объект System.IO.Stream в C #?
  • Значение buffer_size в Dataset.map, Dataset.prefetch и Dataset.shuffle
  • Разница между fprintf, printf и sprintf?
  • Почему ostream_iterator работает не так, как ожидалось?
  • Как получить сообщение об ошибке при сбое openstream
  • Прочитайте файл / URL-адрес по строке в Swift
  • Какова цель flush () в streamах Java?
  • Давайте будем гением компьютера.