我想我会做一些不同的事情。我可能已经把它做得比必要的更详细一点——我担心我可能会因为试图充分利用新的 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
)。如果您想写入多个文件(可以/可以作为 fstreams 打开的东西),您可以在构造函数中指定任意数量的这些名称(当然,在您的系统施加的限制范围内)。对于您不一定有文件名之类的东西,您可以std::cout
按照最初的意图使用。std::cerr
attach
我想我应该补充一点,我对现状并不完全满意。这样做需要进行一些相当认真的重写,但经过一番思考,我认为“正确”的方法可能是让multi::stream
ctor 成为可变参数模板,因此您可以执行以下操作multi::stream icl("c:\\out1.txt", std::cout);
:它会根据参数的类型整理出如何使用每个参数。我可能会在不久的将来更新此答案以包含该功能。
至于第二个问题,我已经写了另一个涵盖基本思想的答案,但可能有点过于复杂,所以你关心的部分可能会在洗牌中迷失,可以这么说 - 它有相当多的逻辑来处理您并不真正关心的行长度(但确实会产生带有指定前缀的每个输出行,就像您想要的那样)。