少し違うことをすると思います。これはおそらく必要以上に手の込んだものでした。C++11 の新しい機能を有効に活用しようとして少し夢中になってしまったのではないでしょうか。とにかく、コードを続けます:
#include <streambuf>
#include <fstream>
#include <vector>
#include <iostream>
#include <initializer_list>
namespace multi {
class buf: public std::streambuf {
std::vector<std::streambuf *> buffers;
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
buf(std::vector<std::ofstream> &buf) {
for (std::ofstream &os : buf)
buffers.push_back(os.rdbuf());
}
void attach(std::streambuf *b) { buffers.push_back(b); }
int_type overflow(int_type c) {
bool eof = false;
for (std::streambuf *buf : buffers)
eof |= (buf -> sputc(c) == traits_type::eof());
return eof ? traits_type::eof() : c;
}
};
class stream : public std::ostream {
std::vector<std::ofstream> streams;
buf outputs;
public:
stream(std::initializer_list<std::string> names)
: streams(names.begin(), names.end()),
outputs(streams),
std::ostream(&outputs)
{ }
void attach(std::ostream &b) {
outputs.attach(b.rdbuf());
}
};
}
int main() {
multi::stream icl({"c:\\out1.txt", "c:\\out2.txt"});
icl.attach(std::cout);
icl << "Blah blah blah" << std::endl;
}
ご覧のとおり、これはすでにマニピュレータを受け入れています (これはだけでなく、どのマニピュレータでも動作するはずですstd::endl
)。複数のファイル (fstream として開くことができるもの) に書き込みたい場合は、コンストラクターでそれらの名前を好きなだけ指定できます (もちろん、システムによって課される制限内で)。std::cout
やのようにstd::cerr
必ずしもファイル名を持っていないものについては、attach
当初の意図どおりに使用できます。
私は、この現状に完全に満足しているわけではないことを付け加えておく必要があると思います. それを行うにはかなり深刻な書き直しが必要ですが、少し考えた後、「正しい」方法はおそらくmulti::stream
'ctor を代わりに可変個引数テンプレートにすることだと思うので、次のようなことができるでしょう: multi::stream icl("c:\\out1.txt", std::cout);
,そして、そのタイプに基づいて各パラメーターの使用方法を整理します。この回答を更新して、その機能をすぐに含めることができます。
2番目の質問に関する限り、基本的な考え方をカバーする別の回答を書きましたが、おそらく少し複雑すぎるため、気になる部分がシャッフルで失われる可能性があります。実際には気にしない行の長さを処理するためのかなりのロジック(ただし、必要に応じて、指定されたプレフィックスを持つ各出力行を生成します)。