5

我目前正在为 an 编写一个包装器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";

这工作得很好。但是,如果我想使用流修饰符,如http://www.cplusplus.com/reference/ios/endlstd::endl中的一个函数,我根本不会编译。

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

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

4

2 回答 2

3

看到这个答案

你会想要

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;
}
于 2013-02-12T10:00:37.623 回答
2

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

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).)

于 2013-02-12T10:05:33.810 回答