multi dimentional vector の resize/fill 関数を template で実装

プログラミングコンテストの問題を解いていて

dp[i][j][k] += dp[i-1][j][k]

みたいに多重配列が必要なときがわりとある。

この多重配列を用意して初期化する方法は2つあって、

  • std::vector を使って多重配列を用意する。
vector<vector<vector<int>>> dp(100,vector<vector<int>>(50,vector<int>(30,0)));
  • スタックに多重配列を確保して memset を使う。
int dp[100][50][30];
memset(dp,0,sizeof(dp));

とかなんだけど、vector の初期化は結構書くのが面倒だし、スタックで配列確保するには予め配列の長さを決め打ちしてないとだめだし、memset での初期化は 0 以外だとできなかったりとちょっと微妙。

そこで multi dimentional vector を簡単に resize/fill できる関数を作ってみた。
(プログラミングコンテスト以外では絶対につかわなさそうだけど。)

こんなふうに使う。

namespace mdv = multi_dimentional_vector;
using namespace std;
int main(int argc, char *argv[])
{
        vector<vector<vector<int>>>  vvv; // 多重 vector を定義
        mdv::resize(vvv,2,5,9);     // 指定分 resize

        vector<vector<vector<double>>>  vvv1;

        // 最後に初期化値をもってくることもできる。int -> double に自動キャスト
        mdv::resize(vvv1,2,5,9,-200); 

        mdv::fill(vvv, 8);   // range とか指定しないで全部 fill する。
        return 0;
}


以下が実装コード

#include<vector>

namespace multi_dimentional_vector {
template<typename T> void resize(std::vector<T> &vec, size_t sz) { vec.resize(sz); }
template<typename T, typename S>
void resize(std::vector<T> &vec, size_t sz, const S &init) { vec.resize(sz, static_cast<T>(init)); }
template<typename T, typename... S>
void resize(std::vector<T> &vec, size_t sz, const S&... follows) {
        vec.resize(sz);
        for (auto &v : vec) resize(v, follows...);
}
template <typename T>
struct has_iterator {
    template <typename U> static char test(typename U::iterator* x);
    template <typename U> static long test(U* x);
    static const bool value = sizeof(test<T>(0)) == 1;
};
template <typename T, typename S>
typename std::enable_if<!has_iterator<T>::value, void>::type
fill(std::vector<T>& vec, const S &value) { std::fill(vec.begin(), vec.end(), static_cast<T>(value)); }

template <typename T, typename S>
typename std::enable_if<has_iterator<T>::value, void>::type
fill(std::vector<T>& vec, const S &value) { for (auto &v : vec) fill(v, value); }

template<typename T, typename... S>
std::vector<T> define(size_t sz, const S&... follows) {
        std::vector<T> vec;
        return std::move(vec);
}
};