4

我正在尝试制作一个类似于 的 C++ 类 std::ostream,它将接受其输入并写入std::ostream构造函数中给定的两个 s。这是与适当的operator<<模板一起:

struct SplitStream
{
    SplitStream(std::ostream & a_, std::ostream & b_) : a(a_), b(b_) {}
    std::ostream & a, & b;
};


template<class T>
const SplitStream & operator << (const SplitStream & sp, const T & x)
{
    sp.a << x;
    sp.b << x;
    return sp;
}

该代码下面的几行,我尝试使用这个类:

void foo(SplitStream & out)
{
    double some_double = 1.23;
    out << "bar" << some_double << std::endl;
}

我得到了这个相当神秘的错误:

... error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'const SplitStream' (or there is no acceptable conversion) ...

我究竟做错了什么?我试图在operator<<没有 const 的情况下进行定义,但它也没有编译。

4

2 回答 2

5

直接的问题是它std::endl不是一个对象,而是一个函数模板,声明如下:

template <typename cT, typename Traits>
std::basic_ostream<cT, Traits>& endl(std::basic_ostream<cT, Traits>&);

要使用这样的函数指针,需要推导模板参数。为此,该类std::basic_ostream<cT, Traits>声明了合适的重载operator<<()

template <typename cT, typename Traits>
std::basic_ostream<cT, Traits>& std::baisic_ostream<cT, Traits>::operator<< (
    std::basic_ostream<cT, Traits>& (*manip)(std::basic_ostream<cT, Traits>&));

这样,编译器可以在std::endl引用函数时推断出正确的实例化。

然而,所有这一切都是完全无关的,因为你想要做的最好完全不同!您应该创建一个合适的流缓冲区并使用一个合理构造std::ostream的自定义流缓冲区。下面是一个如何正确执行的完整示例(我之前发布过但只发布了几十次......):

#include <streambuf>

struct teebuf
    : std::streambuf
{
    std::streambuf* sb1_;
    std::streambuf* sb2_;

    teebuf(std::streambuf* sb1, std::streambuf* sb2)
        : sb1_(sb1), sb2_(sb2) {
    }
    int overflow(int c) {
        typedef std::streambuf::traits_type traits;
        bool rc(true);
        if (!traits::eq_int_type(traits::eof(), c)) {
            traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
                && (rc = false);
            traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
                && (rc = false);
        }
        return rc? traits::not_eof(c): traits::eof();
    }
    int sync() {
        bool rc(true);
        this->sb1_->pubsync() != -1 || (rc = false);
        this->sb2_->pubsync() != -1 || (rc = false);
        return rc? 0: -1;
    }
};

#include <fstream>
#include <iostream>

int main()
{
    std::ofstream fout("tee.txt");
    teebuf        sbuf(fout.rdbuf(), std::cout.rdbuf());
    std::ostream  out(&sbuf);
    out << "hello, world!\n";
}
于 2012-12-18T23:44:16.920 回答
0

另一个答案更好,但为了完整性:

operator<< 中的 SplitStream 引用不应为 const,因为它们正在修改结构包含的流。

template<class T>
SplitStream & operator << (SplitStream & sp, const T & x)
{
    sp.a << x;
    sp.b << x;
    return sp;
}
于 2012-12-19T00:04:21.130 回答