はじめに
C++で多次元配列を実装する場合、C言語スタイルの配列,例えば
int array[3][4][2];
をそのまま使用することも可能です.しかし,この方法ではサイズが固定されており変更ができない上に,代入操作ができないため,扱いが煩雑になることがあります.一方,以下のようにstd::vector
やstd::array
をネストして使用する方法もあります.
std::vector<std::vector<std::vector<int>>> array(3, std::vector<std::vector<int>>(4, std::vector<int>(2)));
多少のメモリオーバーヘッドやアクセスのオーバーヘッドは発生しますが,コピー代入やムーブ代入が可能であり,これらにより操作が容易になり,プログラムの見通しも良くなることが期待できます.ただし,このように宣言記述が複雑になるため,簡潔に定義するためのソースコードを備忘録としてまとめておきます.
ソースコード
std::vector
のネスト
次元(ネストの深さ)はコンパイル時に固定ですが,各次元の大きさは実行時に決定することができます.つまり,ソースコード中の次元3,4,2
は定数でなく変数として実行時に指定することができます.
#include <iostream>
#include <vector>
// ベースケース: 0次元、単一のT型変数を返す
template <typename T> T nested_vector() { return T(); }
// 再帰ケース: 1次元以上、std::vectorをネストして返す
template <typename T, typename... Dims>
auto nested_vector(size_t first, Dims... dims) {
return std::vector<decltype(nested_vector<T>(dims...))>(
first, nested_vector<T>(dims...));
}
int main() {
// 3x4x2のint型3次元配列を作成
auto array = nested_vector<int>(3, 4, 2);
// 値の代入
array[0][0][0] = 1;
array[2][3][1] = 42;
// 値の確認
std::cout << "array[0][0][0] = " << array[0][0][0] << std::endl; // 1
std::cout << "array[2][3][1] = " << array[2][3][1] << std::endl; // 42
return 0;
}
std::array
のネスト
次元(ネストの深さ)と各次元の大きさはコンパイル時に固定です.
#include <array>
#include <iostream>
// ベースケース: 0次元、単一のT型変数を返す
template <typename T> T nested_array() { return T(); }
// 再帰ケース: 1次元以上、std::arrayをネストして返す
template <typename T, size_t first, size_t... Dims> auto nested_array() {
return std::array<decltype(nested_array<T, Dims...>()), first>{};
}
int main() {
// 3x4x2のint型3次元配列を作成
auto array = nested_array<int, 3, 4, 2>();
// 値の代入
array[0][0][0] = 1;
array[2][3][1] = 42;
// 値の確認
std::cout << "array[0][0][0] = " << array[0][0][0] << std::endl; // 1
std::cout << "array[2][3][1] = " << array[2][3][1] << std::endl; // 42
return 0;
}
おわりに
boost::multi_array
を使って,次のように書くこともできます.
boost::multi_array<int, 3> array(boost::extents[3][4][2]);
std::vector
のネストと同様,次元は固定ですが各次元の大きさは実行時に決定することができます.
では、次元自体を実行時に決定することは可能でしょうか?結論としては,C++はPythonのような動的型付けをサポートしていないので,次元によって型が変わるこれらの方法を用いた延長線上では実現できません.