यदि आपके पास यह पूरी तरह से stdlib के भीतर करना है तो आपके पास सही डिजाइन — है।
एक बात: प्रत्येक आउटपुट पर प्रत्येक स्ट्रीमबफ को टीइंग करने के बजाय, इसे उसी क्षेत्र में इस्तेमाल किए जाने वाले स्ट्रीमबफ में से एक के रूप में उपयोग करने के लिए लागू करें, और दूसरों को ओवरफ्लो और सिंक पर कॉपी करें। यह वर्चुअल कॉल को कम करेगा, जो कि स्ट्रीमबफ कैसे काम करता है, इस लक्ष्य में से एक है।
वैकल्पिक रूप से, और आप केवल, stdout & stderr (जो आम है) को संभालने के लिए मानक यूनिक्स tee
कार्यक्रम (या अपने मंच पर समकक्ष) के माध्यम से अपने कार्यक्रम चलाने चाहते हैं, या तो जब कार्यक्रम लागू यह अपने आप को करने से, या फोर्किंग द्वारा कार्यक्रम के भीतर, धाराओं को उपयुक्त के रूप में स्थापित करना, आदि
संपादित करें: आपने मुझे सोचा, और मुझे यह पता होना चाहिए कि यह अधिकार कैसे प्राप्त करें। यहां मेरा firstapproximation है।
#ifndef INCLUDE_GUARD_A629F54A136C49C9938CB33EF8EDE676
#define INCLUDE_GUARD_A629F54A136C49C9938CB33EF8EDE676
#include <cassert>
#include <cstring>
#include <streambuf>
#include <map>
#include <vector>
template<class CharT, class Traits=std::char_traits<CharT> >
struct basic_streamtee : std::basic_streambuf<CharT, Traits> {
typedef std::basic_ios<CharT, Traits> Stream;
typedef std::basic_streambuf<CharT, Traits> StreamBuf;
typedef typename StreamBuf::char_type char_type;
typedef typename StreamBuf::traits_type traits_type;
typedef typename StreamBuf::int_type int_type;
typedef typename StreamBuf::pos_type pos_type;
typedef typename StreamBuf::off_type off_type;
basic_streamtee() : _key_buf(0) {}
basic_streamtee(Stream& a, Stream& b) : _key_buf(0) {
this->pubimbue(a.rdbuf()->getloc());
_set_key_buf(a.rdbuf());
insert(a);
insert(b);
}
~basic_streamtee() {
sync();
for (typename std::map<Stream*, StreamBuf*>::iterator i = _bufs.begin();
i != _bufs.end();
++i)
{
StreamBuf* old = i->first->rdbuf(i->second);
if (old != this) {
old->pubsync();
}
}
}
// add this functionality?
// streambufs would be unconnected with a stream
// easy to do by changing _bufs to a multimap
// and using null pointers for the keys
//void insert(StreamBuf* buf);
//void remove(StreamBuf* buf);
void insert(Stream& s) {
sync();
if (!_bufs.count(&s)) {
if (!_key_buf) {
_set_key_buf(s.rdbuf());
}
_bufs[&s] = s.rdbuf(this);
}
}
void remove(Stream& s) {
sync();
typename std::map<Stream*, StreamBuf*>::iterator i = _bufs.find(&s);
if (i != _bufs.end()) {
StreamBuf* old = i->second;
i->first->rdbuf(i->second);
_bufs.erase(i);
if (old == _key_buf) {
_set_key_buf(_bufs.empty() ? 0 : _bufs.begin()->second);
}
}
}
private:
basic_streamtee(basic_streamtee const&); // not defined
basic_streamtee& operator=(basic_streamtee const&); // not defined
StreamBuf* _key_buf;
std::map<Stream*, StreamBuf*> _bufs;
void _set_key_buf(StreamBuf* p) {
//NOTE: does not sync, requires synced already
_key_buf = p;
_update_put_area();
}
void _update_put_area() {
//NOTE: does not sync, requires synced already
if (!_key_buf) {
this->setp(0, 0);
}
else {
this->setp((_key_buf->*&basic_streamtee::pbase)(),
(_key_buf->*&basic_streamtee::epptr)());
}
}
#define FOREACH_BUF(var) \
for (typename std::map<Stream*, StreamBuf*>::iterator var = _bufs.begin(); \
var != _bufs.end(); ++var)
// 27.5.2.4.1 Locales
virtual void imbue(std::locale const& loc) {
FOREACH_BUF(iter) {
iter->second->pubimbue(loc);
}
}
// 27.5.2.4.2 Buffer management and positioning
//virtual StreamBuf* setbuf(char_type* s, std::streamsize n); // not required
//virtual pos_type seekoff(off_type off, std::ios_base::seekdir way,
// std::ios_base::openmode which); // not required
//virtual pos_type seekpos(pos_type sp, std::ios_base::openmode which); // not required
virtual int sync() {
if (!_key_buf) {
return -1;
}
char_type* data = this->pbase();
std::streamsize n = this->pptr() - data;
(_key_buf->*&basic_streamtee::pbump)(n);
FOREACH_BUF(iter) {
StreamBuf* buf = iter->second;
if (buf != _key_buf) {
buf->sputn(data, n); //BUG: ignores put errors
buf->pubsync(); //BUG: ignroes errors
}
}
_key_buf->pubsync(); //BUG: ignores errors
_update_put_area();
return 0;
}
// 27.5.2.4.3 Get area
// ignore input completely, teeing doesn't make sense
//virtual std::streamsize showmanyc();
//virtual std::streamsize xsgetn(char_type* s, std::streamsize n);
//virtual int_type underflow();
//virtual int_type uflow();
// 27.5.2.4.4 Putback
// ignore input completely, teeing doesn't make sense
//virtual int_type pbackfail(int_type c);
// 27.5.2.4.5 Put area
virtual std::streamsize xsputn(char_type const* s, std::streamsize n) {
assert(n >= 0);
if (!_key_buf) {
return 0;
}
// available room in put area? delay sync if so
if (this->epptr() - this->pptr() < n) {
sync();
}
// enough room now?
if (this->epptr() - this->pptr() >= n) {
std::memcpy(this->pptr(), s, n);
this->pbump(n);
}
else {
FOREACH_BUF(iter) {
iter->second->sputn(s, n);
//BUG: ignores put errors
}
_update_put_area();
}
return n;
}
virtual int_type overflow(int_type c) {
bool const c_is_eof = traits_type::eq_int_type(c, traits_type::eof());
int_type const success = c_is_eof ? traits_type::not_eof(c) : c;
sync();
if (!c_is_eof) {
char_type cc = traits_type::to_char_type(c);
xsputn(&cc, 1);
//BUG: ignores put errors
}
return success;
}
#undef FOREACH_BUF
};
typedef basic_streamtee<char> streamtee;
typedef basic_streamtee<wchar_t> wstreamtee;
#endif
अब, यह परीक्षण पूरा से दूर है (जब यह टूट जाता है, तो आप दोनों टुकड़े रखने के लिए मिलता है।), लेकिन यह काम करने के लिए लगता है:
#include "streamtee.hpp"
#include <cassert>
#include <iostream>
#include <sstream>
int main() {
using namespace std;
{
ostringstream a, b;
streamtee tee(a, b);
a << 42;
assert(a.str() == "42");
assert(b.str() == "42");
}
{
ostringstream a, b;
streamtee tee(cout, a);
tee.insert(b);
a << 42 << '\n';
assert(a.str() == "42\n");
assert(b.str() == "42\n");
}
return 0;
}
यह एक साथ रखें एक फ़ाइल के साथ:
#include "streamtee.hpp"
#include <iostream>
#include <fstream>
struct FileTee {
FileTee(std::ostream& stream, char const* filename)
: file(filename), buf(file, stream)
{}
std::ofstream file;
streamtee buf;
};
int main() {
using namespace std;
FileTee out(cout, "stdout.txt");
FileTee err(clog, "stderr.txt");
streambuf* old_cerr = cerr.rdbuf(&err.buf);
cout << "stdout\n";
clog << "stderr\n";
cerr.rdbuf(old_cerr);
// watch exception safety
return 0;
}
मुझे यहां जवाब पसंद है: http://stackoverflow.com/a/13978705/2662901 – feetwet