4

に似た C++ クラスを作成しようとしています 。これは、入力を受け取り、コンストラクターで指定されたstd::ostream2 つの に書き込みます。ここでは、適切なテンプレートstd::ostreamと一緒に: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) ...

私は何を間違っていますか?const なしで定義しようとしましoperator<<たが、どちらもコンパイルされませんでした。

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 に答える