std :: ostringstream打印c-string的地址而不是其内容

Mat*_* M. 19 c++ stream

我偶然发现了一个我最初无法解释的奇怪行为(见ideone):

#include <iostream>
#include <sstream>
#include <string>

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<std::ostringstream&>(s2 << "some data").str()
            << "\n";

  std::cout << "Inline        : "
            << dynamic_cast<std::ostringstream&>(
                 std::ostringstream() << "some data"
               ).str()
            << "\n";
}
Run Code Online (Sandbox Code Playgroud)

给出输出:

Reference     : 0x804a03d
Regular Syntax: some data
Semi inline   : some data
Inline        : 0x804a03d
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,在最后一次演员表中我们有地址,而不是内容!

为什么会这样 ?

Naw*_*waz 19

表达式std::ostringstream()创建一个临时的,并且operator<<const char*参数作为自由函数,但是这个自由函数不能在临时函数上调用,因为函数的第一个参数的类型是std::ostream&不能绑定到临时对象的.

话虽如此,<<std::ostringstream() << "some data"解析为调用重载的成员函数void*,打印地址.请注意,可以在临时上调用成员函数.

为了调用自由函数,你需要将临时值(即rvalue)转换为左值,这是你可以做的一个技巧:

 std::cout << "Inline        : "
            << dynamic_cast<std::ostringstream&>(
                 std::ostringstream().flush() << "some data"
               ).str()
            << "\n";
Run Code Online (Sandbox Code Playgroud)

也就是说,std::ostringstream().flush()返回std::ostream&意味着,现在可以调用自由函数,将返回的引用作为第一个参数传递.

此外,你不需要在dynamic_cast这里使用(这很慢,因为它在运行时完成),因为对象的类型是众所周知的,所以你可以使用static_cast(这在编译时很快就完成了 -时间):

 std::cout << "Inline        : "
            << static_cast<std::ostringstream&>(
                 std::ostringstream().flush() << "some data"
               ).str()
            << "\n";
Run Code Online (Sandbox Code Playgroud)

应该工作得很好.

  • 哇!你的解决方法比我的更好.绝对有一天,当我想要将Stroustrup抨击以排除与非const的绑定时:x (3认同)
  • 精确!我花了一个小时来弄清楚:x我已经在下面发布了我的调查......并且不知何故希望我早些时候问过(尽管它不会像教育那样). (2认同)
  • @FreakEnum:你**不能**写这个:`A&a = A()`,因为表达式`A()`创建一个类型为'A`的临时对象,但是非const引用(在左边 - 根据语言规范,赋值的一方)不能绑定到临时的.但是一旦你把它作为const引用,那么绑定是可能的; 也就是说,你**可以**写这个:`一个const&a = A()`.类似地,`std :: ostream&`是一个非const引用,它不能绑定到由`std :: ostringstream()`表达式创建的临时对象. (2认同)

Che*_*Alf 9

临时不能绑定到对非const形式参数的引用.

因此,非会员<<不被接听.

你会得到void*版本.

C++ 11通过添加非成员rvalue流插入器函数来修复此问题,

C++
11§27.7.3.9右值流插入
[ostream.rvalue] 1 效果: 2 返回:
template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);

os << x
os

干杯和hth.