Hi! I hope you are doing well.
If you are in love(!) with vectors and you use them a lot, you probably know that defining a multidimensional vector is just a pain in the neck! For example if you are trying to define a 3 dimensional vector with (n, m, k)
as dimensions you have to write it like this :
vector<vector<vector<int>>> a(n, vector<vector<int>>(m, vector<int>(k)));
Then you change your mind and realize that your data will not fit in an int
. You decide to change it to long long
.
vector<vector<vector<long long>>> a(n, vector<vector<int>>(m, vector<int>(k)));
[HITS COMPILE BUTTON] Oops! won't compile (G++ really get's mad at you). Go on and change inner vectors as well.
vector<vector<vector<long long>>> a(n, vector<vector<long long>>(m, vector<long long>(k)));
So if you want a 100 dimensional vector of long long
s, you literally have to say it 100 times to the compiler that you want your data to be long long
.
Well what's the solution?
N dimensional vector using template meta programming
So yes, there is this thing called template meta programming which I'm not going to discuss here. But you can do cool things with it! One of the cool things is just N dimensional vector (basically D dimensional!). Here's the code:
template<int D, typename T>
struct Vec : public vector<Vec<D - 1, T>> {
static_assert(D >= 1, "Vector dimension must be greater than zero!");
template<typename... Args>
Vec(int n = 0, Args... args) : vector<Vec<D - 1, T>>(n, Vec<D - 1, T>(args...)) {
}
};
template<typename T>
struct Vec<1, T> : public vector<T> {
Vec(int n = 0, const T& val = T()) : vector<T>(n, val) {
}
};
This is essentially publicly inheriting from vector<vector<vector< ... vector<T> ... >>>
in which vector
appears D
times!
It has a constructor which takes dimensions in order and if you want to initialize your multidimensional vector with some value you can pass that value to the constructor as the last argument otherwise it will be initialized with zero (or if it's a class it will be initialized using default constructor). If you provide less than D
numbers to the constructor, following dimensions will have length equal to zero.
A few examples :
Vec<2, int> a(10, 50); // int a[10][50] initialized with zero
Vec<3, double> b(n, m, k, 3.14); // double b[n][m][k] initialized with 3.14
Vec<3, long long> c(5, 5); // the third dimension has no value yet
c[0][0].push_back(100); // now c[0][0][0] has a value (100) but others don't
Vec<4, int> d(10, 10);
d[2][3].push_back(Vec<1, int>(100, 12345)); // now d[2][3][0] is a vector with 100 values of 12345
Vec<1, string> e; // just blank vector of strings
Based on C++11 (or above) standard this code will compile.
Template arguments must be compile time constants, for example Vec<n, int>
in which n
is the user input, won't compile, which makes a lot of sense.