Rangeの内容を出力する

こんな感じで使います。

int main()
{
    using namespace std;
    vector<vector<string>> v{{"abc", "def"}, {"ghi", "jkl"}};
    cout << iorate::print(v);
}

出力

{{abc,def},{ghi,jkl}}

実装

#include <iostream>
#include <iterator>
#include <type_traits>

namespace iorate {

template <class T>
struct print_holder
{
    print_holder(T const &v) : v_(v) {}
    T const &v_;
};

template <class T>
inline print_holder<T> print(T const &v) { return print_holder<T>(v); }

template <class Char>
struct print_traits;

template <>
struct print_traits<char>
{
    static char const left_curly_bracket = '{';
    static char const right_curly_bracket = '}';
    static char const comma = ',';
};

template <>
struct print_traits<wchar_t>
{
    static wchar_t const left_curly_bracket = L'{';
    static wchar_t const right_curly_bracket = L'}';
    static wchar_t const comma = L',';
};

template <class Char, class CharTraits, class T>
inline
auto output(std::basic_ostream<Char, CharTraits> &os, print_holder<T> h, int) ->
typename std::enable_if<!std::is_array<T>::value, decltype(os << h.v_)>::type
{
    return os << h.v_;
}

template <class Char, class CharTraits, class T>
inline
std::basic_ostream<Char, CharTraits> &
output(std::basic_ostream<Char, CharTraits> &os, print_holder<T> h, ...)
{
    os << print_traits<Char>::left_curly_bracket;
    bool first = true;
    for (auto it = std::begin(h.v_); it != std::end(h.v_); ++it) {
        if (first)
            first = false;
        else
            os << print_traits<Char>::comma;
        os << print(*it);
    }
    os << print_traits<Char>::right_curly_bracket;
    return os;
}

template <class Char, class CharTraits, class T>
inline
std::basic_ostream<Char, CharTraits> &
operator <<(std::basic_ostream<Char, CharTraits> &os, print_holder<T> h)
{
    return output(os, h, 0);
}

}

SFINAEとオーバーロードの合わせ技で、

  1. operator << で出力可能で、かつ配列でない場合はそのまま出力
  2. それ以外の場合はrangeと見なし、それぞれの要素をprintに渡して再帰的に出力

するようにしています。