我想我会做点事情有点不同。我可能已经做了一些比必要更复杂的工作 - 恐怕我可能会因为尝试使用新的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);
,它会整理出如何根据其类型使用每个参数。我可能会很快更新这个答案以包含那个功能。
至于第二个问题,我写了another answer,涵盖了基本的想法,但可能有点过于详细,所以你关心的部分可能会迷失在洗牌,可以这么说 - - 处理不真正关心的行长度有相当多的逻辑(但是会像你想的那样产生具有指定前缀的每个输出行)。
问题1:Google运算符超载,您会看到很多示例。 – dutt 2013-04-21 19:40:23
我很清楚运算符重载是如何工作的,但是这里似乎有点复杂,因为有大量的数据类型可以输入OutputMan,就像一个整数。当然有更好的方法。 – 2013-04-21 19:41:48
您可以为可能需要特殊处理的类型使用具有特定模板重载/实例(不确定其称谓)的模板。 – dutt 2013-04-21 19:44:02