我试图将一些调试输出添加到C ++ 03项目中并得到一些奇怪的结果。这是简化的测试代码:
#include <fstream>
int main()
{
{
std::ofstream file("/tmp/test.txt");
file << "hello" << " ... OK, this works\n";
}
std::ofstream("/tmp/test.txt",std::ios_base::app) << "hello"
<< " ... no, I mean hello!\n";
}
出于某种原因,这是编译后得到的结果:
$ g++ test.cpp -o test && ./test && cat /tmp/test.txt
hello ... OK, this works
0x80487fe ... no, I mean hello!
为什么在将字符串输出到未命名的std::ofstream
对象的情况下会得到十六进制数?为什么第二个字符串的后续输出有效?
答案 0 :(得分:8)
我们用于将C字符串传递给operator<<
的常用std::ostream
是declared as自由函数
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
未命名的std::ofstream
对象是临时变量,临时变量不能绑定到nonconst引用,因此此运算符重载不参与重载决策。而是采用最接近的匹配,成员函数
std::basic_ostream& std::basic_ostream::operator<<(const void*);
,它采用类型擦除指针并只打印其值。由于可以在对象是临时对象的情况下调用成员函数,因此可以解决这个问题。这解释了输出中的十六进制数。现在,此运算符返回引用std::basic_ostream&
。由于它不再是临时对象而是对某些非对象对象的引用,因此可以成功调用operator<<
的{{1}}的常规自由函数重载。这就是第二个字符串按预期打印的原因。
请注意,由于C ++ 11代码将按预期工作,因为我们有一个额外的const char*
重载,它接受一个右值引用:
operator<<
,临时绑定到右值引用。
要使代码在C ++ 03中工作,您可以使用成员函数template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
,它返回对象的nonconst引用,并且对{没有任何用户可见的副作用{1}}对象:
std::ostream::flush()