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); } };
- resize の方は可変数 template で前から引数を処理しているだけ。
- fill は has_iterator で iterate できる T と判定されたなら vector として再帰、そうでなければ std::fill を呼び出す。
- has_iterator は C++: SFINAE | On C++ and other OOPscenities を参考にした。