C++ iostream 的包装类,请使用带有运算符的 std::endl 等流修饰符<<

C++ wrapper class for iostream, use stream modifiers like std::endl with operator<<

本文关键字:lt endl std 包装类 iostream 请使用 运算符 C++      更新时间:2023-10-16

我目前正在为std::stringstream编写包装器,我想通过我的类将所有operator<<调用转发到std::stringstream。这个现在还可以(由于这个问题:STL流的包装类:正向运算符<<调用),但它仍然有一个问题。

假设我有以下代码:

class StreamWrapper {
private:
    std::stringstream buffer;
public:
    template<typename T>
    void write(T &t);
    template<typename T>
    friend StreamWrapper& operator<<(StreamWrapper& o, T const& t);
    // other stuff ...
};

template<typename T>
StreamWrapper& operator<<(StreamWrapper& o, T const& t) {
    o.write(t);
    return o;
}
template<typename T>
void StreamWrapper::write(T& t) {
    // other stuff ...
    buffer << t;
    // other stuff ...
}

如果我现在这样做:

StreamWrapper wrapper;
wrapper << "text" << 15 << "stuff";

这很好用。但是,如果我想使用像std::endl这样的流修饰符,它是根据http://www.cplusplus.com/reference/ios/endl,我根本不编译。

StreamWrapper wrapper;
wrapper << "text" << 15 << "stuff" << std::endl;

为什么?如何转发流修饰符?

看看这个答案。

你会想要

typedef std::ostream& (*STRFUNC)(std::ostream&);
StreamWrapper& operator<<(STRFUNC func)  // as a member, othewise you need the additional StreamWrappe& argument first
{
  this->write(func);
  return *this;
}

您似乎在做一些额外的工作。我通常使用:

class StreamWrapper
{
    // ...
public:
    template <typename T>
    StreamWrapper& operator<<( T const& obj )
    {
        //  ...
    }
};

使用现代编译器,这个应该适用于所有混凝土类型。问题是操纵器是模板函数,因此编译器无法执行模板参数类型演绎解决方案是提供非模板重载对于操纵器类型:

StreamWrapper& operator<<( std::ostream& (*pf)( std::ostream& ) )
{
    //  For manipulators...
}
StreamWrapper& operator<<( std::basic_ios<char>& (*pf)( std::basic_ios<char>& )
{
    //  For manipulators...
}

操纵器的类型推导将失败,但编译器将拾取这些以解决函数过载问题。

(注意,对于std::setw(int)之类的东西,您可能需要更多。)