備忘録 @ ウィキ
multi_stream
最終更新:
mlnk
-
view
概要
複数のostreamへ出力するストリームラッパクラス。
コンストラクタの引数の展開にBoostを使ってるので要Boost。
手書きすればBoostなしでも可。
使い方
void func()
{
std::ofstream of;
of.open("somefile")
util::multi_ostream(std::cout, of);
mt << "foobar" << std::endl; // 標準出力とファイルに"foobar"が出力される
}
コード
/** @file multi_stream.h
* @breif 複数のostreamへ出力するストリームクラス
*/
#ifndef UTIL_MULTI_STREAM_H
#define UTIL_MULTI_STREAM_H
#include <iostream>
#include <vector>
#include <boost/preprocessor.hpp>
namespace util {
namespace detail {
//! コンストラクタで受け付けるostreamの最大数
#define ARGUMENT_MAX_COUNT 5
#define OSTREAM_ARRAY_ASSIGNMENT(z, n, data) outs_[n]=BOOST_PP_CAT(&os, n);
#define BOOST_PP_LOCAL_MACRO(n) \
basic_multi_streambuf(BOOST_PP_ENUM_PARAMS(n, std::basic_ostream<Ch BOOST_PP_COMMA() Tr>& os)) \
: outs_(n), buf_(16) \
{ \
setp(&(buf_[0]), (&(buf_[0])+buf_.size())); \
BOOST_PP_REPEAT(n, OSTREAM_ARRAY_ASSIGNMENT, ~) \
}
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_PP_EXPAND(ARGUMENT_MAX_COUNT))
/* 複数のostreamへ出力するためのstreambufクラス */
template <class Ch, class Tr=std::char_traits<Ch> >
class basic_multi_streambuf : public std::basic_streambuf<Ch,Tr> {
public:
typedef typename std::basic_streambuf<Ch, Tr>::int_type int_type;
#include BOOST_PP_LOCAL_ITERATE()
void add(std::basic_ostream<Ch, Tr>& os)
{
outs_.push_back(&os);
}
~basic_multi_streambuf()
{}
protected:
int_type overflow(int_type c=Tr::eof())
{
if(c!=Tr::eof()) {
const size_t pos = pptr()-pbase();
if(buf_.size() <= pos+1) {
buf_.resize(2*buf_.size());
setp(&(buf_[0]), (&(buf_[0])+buf_.size()));
pbump(pos);
}
*pptr() = Tr::to_char_type(c);
pbump(1);
return Tr::not_eof(c);
}
return Tr::eof();
}
int sync()
{
const size_t pos = pptr()-pbase();
for(ostreams::iterator it=outs_.begin(); it!=outs_.end(); ++it) {
(*it)->write(&(buf_[0]), pos);
(*it)->flush();
}
pbump(pbase()-pptr());
return 0;
}
private:
explicit basic_multi_streambuf<Ch, Tr>(const basic_multi_streambuf<Ch, Tr>&);
basic_multi_streambuf<Ch, Tr> &operator=(const basic_multi_streambuf<Ch, Tr>&);
typedef std::vector<std::basic_ostream<Ch,Tr>* > ostreams;
ostreams outs_;
std::vector<Ch> buf_;
};
#define BOOST_PP_LOCAL_MACRO(n) \
basic_multi_ostream(BOOST_PP_ENUM_PARAMS(n, std::basic_ostream<Ch BOOST_PP_COMMA() Tr>& os)) \
: std::basic_iostream<Ch,Tr>(&streambuf_), streambuf_(BOOST_PP_ENUM_PARAMS(n, os)) \
{}
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_PP_EXPAND(ARGUMENT_MAX_COUNT))
/* 複数のostreamへ出力するためのラッパークラス */
template <class Ch, class Tr=std::char_traits<Ch> >
class basic_multi_ostream : public std::basic_iostream<Ch,Tr> {
public:
#include BOOST_PP_LOCAL_ITERATE()
~basic_multi_ostream()
{}
void add(std::basic_ostream<Ch, Tr>& os)
{
streambuf_.add(os);
}
private:
explicit basic_multi_ostream(const basic_multi_ostream&);
basic_multi_ostream &operator=(const basic_multi_ostream&);
basic_multi_streambuf<Ch, Tr> streambuf_;
};
}
typedef detail::basic_multi_ostream<char> multi_ostream;
typedef detail::basic_multi_ostream<wchar_t> multi_wostream;
#undef ARGUMENT_MAX_COUNT
#undef OSTREAM_ARRAY_ASSIGNMENT
}
#endif