为了开始,最简单的解决方案是获取编译器考虑的可能重载列表,例如尝试
这样做:
X x;
std::cout << x << "\n";
其中X
是一种没有任何流重载的类型,它产生以下可能的重载列表:
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 <typename T>
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";
输出预期结果。
flush
比其他方法更好。 - NawazA & a = A()
,因为表达式A()
创建了一个类型为A
的临时对象,但是根据语言规范,非const引用(在赋值的左侧)无法绑定到临时对象。但是一旦将其变为const引用,则绑定就成为可能;也就是说,你可以写成这样:A const & a = A()
。同样地,std::ostream&
是一个非const引用,无法绑定到由表达式std::ostringstream()
创建的临时对象。 - Nawaz