IO操纵器作为模板参数



我正在尝试使用一个类,让我们称它为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::ostreamoperator<<工作的所有类型,模板都可以很好地实例化。

这适用于所有常见类型,但当我尝试传递一些流操纵器(如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的类型。

所以,我的问题是:

  1. 有办法让它工作吗
  2. 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;
}

最新更新