我正在尝试使用一个类,让我们称它为stream_wrapper
。它包含std::ostream
对象的值(或对其的引用(作为其字段之一。
我只想重载<<
运算符,这样我就可以像使用普通流一样使用这个包装器。我的第一个想法就是把它写成一个函数模板。
示例:
class stream_wrapper
{
std::ostream& stream;
template<typename Output>
friend stream_wrapper& operator<<(stream_wrapper& s, Output output)
public:
stream_wrapper(std::ostream& stream) : stream(stream) {}
}
template<typename Output>
stream_wrapper& operator<<(stream_wrapper& s, Output output)
{
s.stream << output;
return s;
}
这个想法是,对于std::ostream
的operator<<
工作的所有类型,模板都可以很好地实例化。
这适用于所有常见类型,但当我尝试传递一些流操纵器(如std::endl
(时会失败。
示例:
int main()
{
stream_wrapper s(std::cout);
int a = 1;
double b = 5;
s << a << ' ' << b << 'n'; // WORKS
s << std::endl; // DOESN'T COMPILE
}
这失败了,因为编译器无法推导出std::endl
的类型。
所以,我的问题是:
- 有办法让它工作吗
- 像
std::endl
这样的东西是什么类型的
谢谢!
首先,重载的operator<<
缺少一个return *this;
语句。
其次,I/O操纵器被实现为将流对象作为输入的函数。例如,std::endl
是这样声明的:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
std::basic_ostream
有一个过载的operator<<
,它接受这样一个函数:
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
std::basic_ostream::operator<<
的这种过载将调用以*this
为输入参数的func()
,例如:
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) )
{
return func(*this);
}
该机制允许std::endl
(和其他操纵器(通过operator<<
与任何std::ostream
对象一起使用。
因此,在您的示例中,s << std::endl
不编译,因为std::endl
期望的是std::ostream
对象,而不是stream_wrapper
对象。
要在包装器中修复此问题,您必须添加operator<<
的额外重载,以处理可用的各种I/O操纵器,例如:
class stream_wrapper
{
std::ostream& stream;
template<typename Output>
friend stream_wrapper& operator<<(stream_wrapper&, const Output &);
friend stream_wrapper& operator<<(stream_wrapper&, std::ios_base& (*)(std::ios_base&) );
friend stream_wrapper& operator<<(stream_wrapper&, std::ios& (*)(std::ios&) );
friend stream_wrapper& operator<<(stream_wrapper&, std::ostream& (*)(std::ostream&) );
public:
stream_wrapper(std::ostream& stream) : stream(stream) {}
}
template<typename Output>
stream_wrapper& operator<<(stream_wrapper& s, const Output &output)
{
s.stream << output;
return *this;
}
stream_wrapper& operator<<(stream_wrapper& s, std::ios_base& (*func)(std::ios_base&) )
{
s.stream << func;
// or: func(s.stream);
return *this;
}
stream_wrapper& operator<<(stream_wrapper& s, std::ios& (*func)(std::ios&) )
{
s.stream << func;
// or: func(s.stream);
return *this;
}
stream_wrapper& operator<<(stream_wrapper& s, std::ostream& (*func)(std::ostream&) )
{
s.stream << func;
// or: func(s.stream);
return *this;
}