コンテナをストリーム出力

(vectorとかlistとか)コンテナの中身を確認したくてストリームに出力しようと思っても、
コンテナ自体にはoperator<<が定義されていないのでそのままostreamに出力することはできません。

だからといってコンテナの要素をイテレータでたどるために毎回

for(my_container_t::iterator it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it;
}

とか書くのは面倒です。
かといって上のコードをそのまま関数にするのもstd::coutしか使用できないってことで汎用性がないうえ、
せっかくのoperator<<の仕組みを使えないのは残念です。
(他にはstd::ostream_iteratorを使う方法

std::copy(vec.begin(), vec.end(), std::ostream_iterator<my_container_t::value_type>(std::cout));

もありますね。)
コンテナの要素をよしなに出力してくれて、出力先は好きなostreamを使えて
operator<<の形で書ける何かがあると嬉しいですね。

to_ostream_outputtableというクラスを作りました。
こいつを使えば、コンテナをストリームに出力可能にすることができます。

#include <boost/test/minimal.hpp>

#include <iostream>
#include <list>
#include <string>
#include <sstream>
#include <vector>

#include <hwm/to_ostream_outputtable.hpp>

struct TestClass
{
    int         age_;
    std::wstring name_;
    TestClass(int age, std::wstring const &name)
        :   age_(age)
        ,   name_(name)
    {}

    template<class CharType>
    friend
        std::basic_ostream<
            CharType,
            std::char_traits<CharType>
        > & 
        operator<<(
            std::basic_ostream<
                CharType,
                std::char_traits<CharType>
            > &os,
            TestClass const &t )
    {
        return
            os << L"{age : " << t.age_ << L", name : " << t.name_ << L"}";
    }
};

int test_main(int argc, char **argv)
{
    std::vector<std::string> strings;
    strings.push_back("hello");
    strings.push_back("world");
    strings.push_back("!");

    std::list<TestClass> daughters;
    daughters.push_back(TestClass(14, L"空"));
    daughters.push_back(TestClass(10, L"美羽"));
    daughters.push_back(TestClass(3, L"ひな"));

    std::stringstream ss;
    std::wstringstream ws;

    ss << hwm::to_os << strings;
	
    //(0番目の要素, 1番目の要素, 2番目の要素, ...)という風に出力される。
    BOOST_CHECK(ss.str() == "(hello, world, !)");

    //windowsならワイド文字列のwcoutに必要になるかも。それと他の環境のことは知らない。
    setlocale(LC_ALL, "japanese");

   //wide文字列用のostreamにもそのまま使える。
    std::wcout << L"ハッピハッピガー" << hwm::to_os << daughters << L"ハッピハッピガー" << std::endl;
    //ハッピハッピガー({age : 14, name : 空}, {age : 10, name : 美羽}, {age : 3, name : ひな})ハッピハッピガー
	
    return 0;
}

hwm/to_ostream_outputtable.hpp

#ifndef HWM_TOOSTREAMOUTPUTTABLE_HPP
#define HWM_TOOSTREAMOUTPUTTABLE_HPP

#include <boost/range/iterator.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>

namespace hwm {

namespace ostream_outputtable_detail {

    template<class CharType>
    struct ostream_output_impl
    {
        typedef
            std::basic_ostream<
                CharType,
                std::char_traits<CharType>
            >
        ostream_type;

        ostream_output_impl(ostream_type &os)
            :   os_(os)
        {}

        template<class Container>
        ostream_type & operator<< (Container &ct)
        {
            typedef typename boost::range_iterator<Container>::type iterator;

            iterator it         = boost::begin(ct);
            iterator const end  = boost::end(ct);

            if(it == end) {
                os_ << "()";
            } else {
                os_ << "(";
                for( ; ; ) {
                    os_ << *it;
                    ++it;
                    if(it != end) {
                        os_ << ", ";
                    } else {
                        os_ << ")";
                        break;
                    }
                }
            }
            return os_;
        }

        ostream_type &os_;
    };

    struct to_ostream_outputtable
    {
        template<class CharType>
        friend
        ostream_output_impl<CharType>
            operator<< (
                std::basic_ostream<
                    CharType,
                    std::char_traits<CharType>
                > &os,
                to_ostream_outputtable const &t )
        {
            return ostream_output_impl<CharType>(os);
        }
    };
}   //namespace ostream_outputtable_detail

static ostream_outputtable_detail::to_ostream_outputtable const to_os = {};

}   //namespace hwm

#endif  //HWM_TOOSTREAMOUTPUTTABLE_HPP

ostreamによしなに出力したいだけなので、Pythonとかのタプルの形式で決め打ちしています
他の形式で出力するためにポリシークラスを用意したりするともっと便利になるかもですね、でも面倒なのでやってません。
直後に来るコンテナを出力したあとはただの元のostreamに戻るので、
複数のコンテナを出力するときは毎回コンテナの直前にhwm::to_osを置くようにします。

それから、本当はストリーム側じゃなくてコンテナ側をいじってostreamに出力可能なようにする方が行儀がいいのかも・・・?