読者です 読者をやめる 読者になる 読者になる

tak0kadaの何でもノート

発声練習、生存確認用。

医学関連は 医学ノート

テンプレートで任意の多次元の配列を出力する

C、C++

任意の次元の配列をprintする関数が欲しくなったが、単純にベタ書きする方法だと次元が決まっている場合しか対応できないのでテンプレートの再帰を用いたプログラムを書いてみた。

次元を調べてみる(練習)

template<typename T, size_t n>
constexpr int dim(const T (&arr)[n])
{
    return 1;
}

template<typename T, size_t n, size_t m>
constexpr int dim(const T (&arr)[n][m])
{
    return dim(arr[0]) + 1;
}

配列を出力する

テンプレートは強力なので、テンプレート引数に必要な情報を押し込んでプログラムすることも可能だが強引なことはせず、再帰の際に必要な情報は関数の引数として渡すことにした。当初は構造体に渡す引数をまとめると便利な気がしていたが、実際はstd::stringそのもので十分だった。

#include <iostream>
#include <string>


// store information to format matrix output
struct Fmt
{
    std::string end_indent;
};

template<typename T, size_t n>
std::ostream& _print_impl(std::ostream &os, const T (&arr)[n], const Fmt &fmt)
{
    os << '{';
    for (auto i = 0; i < n - 1; ++i)
    {
        os << arr[i] << ", ";
    }
    os << arr[n - 1] << '}';
    return os;
}

template<typename T, size_t n, size_t m>
std::ostream& _print_impl(std::ostream &os, const T (&arr)[n][m], const Fmt &fmt)
{
    os << '{';
    for (auto i = 0; i < n - 1; ++i)
    {
        _print_impl(os, arr[i], Fmt{fmt.end_indent + " "});
        os << ",\n"
           << fmt.end_indent + " ";
    }
    _print_impl(os, arr[n - 1], Fmt{fmt.end_indent + " "});
    os << '}';
    return os;
}

template<typename T, size_t n>
void print(const T (&arr)[n])
{
    _print_impl(std::cout, arr, Fmt{""});
    std::cout << std::endl;
}

template<typename T, size_t n, size_t m>
void print(const T (&arr)[n][m])
{
    _print_impl(std::cout, arr, Fmt{""});
    std::cout << std::endl;
}

int main()
{
    int arr0[2] = {1,2};
    print(arr0);
    int arr1[2][2] = {{1,2}, {2,3}};
    print(arr1);
    int arr[2][2][2] = {{{-1, 0}, {0, 1}}, {{1, 2}, {2, 3}}};
    print(arr);

    return 0;
}

こんな感じの出力になる。

{1, 2}
{{1, 2},
 {2, 3}}
{{{-1, 0},
  {0, 1}},
 {{1, 2},
  {2, 3}}}

operator<<は文字列の出力で以下のエラーが出て厄介なので定義しないことにした。

ts.cpp:56:6: error: use of overloaded operator '<<' is
      ambiguous (with operand types 'std::ostream' (aka
      'basic_ostream<char>') and 'const char [3]')

追記

多次元の配列を生成するためのテンプレートなら検索すればたくさん見つかる。