備忘録 @ ウィキ

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
人気記事ランキング
目安箱バナー