任意の次元の配列を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]')
追記
多次元の配列を生成するためのテンプレートなら検索すればたくさん見つかる。