Probably there is a better way for you to achieve what you want to do, but you can use templates like:
#include <vector>
#include <cstddef>
template <size_t DEPTH>
struct helper;
template <>
struct helper<1>{
using type = std::vector<int>;
};
template <size_t DEPTH>
struct helper {
using type = std::vector<typename helper<DEPTH-1>::type>;
};
template <size_t DEPTH>
typename helper<DEPTH>::type* cast_to_vector(void* data){
return static_cast<typename helper<DEPTH>::type*>(data);
}
int main() {
std::vector<std::vector<std::vector<int>>> vec{};
void * example = &vec;
std::vector<std::vector<std::vector<int>>>* vec_prt = cast_to_vector<3>(example);
return 0;
}
This will recursively construct the type you want. You can also ignore the cast_to_vector
function and use the helper
classes.
If these are not compile time constants then this might be more problematic. One easy, but potentially very messy method of working with this is by using a custom datatype, like:
template <typename T>
class Tree : public std::vector<Tree<T>>{
public:
operator T&() { return val; }
Tree& operator =(const T& new_val) {
this->val = new_val;
return *this;
}
private:
T val;
};
This implementation does miss a lot of things you'd want, but it does work for demonstration. You can then access this iteratively like a[0][2][3] = 10;
An other option (especially useful if the data's size is constant), would be to implement a new object, something like:
template <typename T, bool ret_self = true>
class Tree {
public:
Tree(const std::vector<size_t>& arr_sizes)
: data_size{arr_sizes}
, data{std::make_shared<T[]>(prod(arr_sizes))}
, array{data.get()} {}
Tree<T>& operator[] (size_t index) {
std::vector<size_t> new_sizes = data_size;
new_sizes.erase(new_sizes.begin());
if (new_sizes.empty())
return Tree<T>(new_sizes, this->data, array + prod(new_sizes)*index);
return Tree<T,false>(new_sizes, this->data, array + prod(new_sizes)*index);
}
private:
Tree(std::vector<size_t>&& arr_sizes, const std::shared_ptr<T>& d, T* arr)
: data_size{arr_sizes}
, data_size{d}
, array{arr} {}
std::vector<size_t> data_size;
std::shared_ptr<T> data;
T* array;
};
template <typename T>
class Tree<T,false> {
public:
Tree(const std::vector<size_t>& arr_sizes)
: data_size{arr_sizes}
, data{std::make_shared<T[]>(prod(arr_sizes))}
, array{data.get()} {}
T& operator[] (size_t index) {
return this->array[index];
}
private:
Tree(std::vector<size_t>&& arr_sizes, const std::shared_ptr<T>& d, T* arr)
: data_size{arr_sizes}
, data_size{d}
, array{arr} {}
std::vector<size_t> data_size;
std::shared_ptr<T> data;
T* array;
};
As stated however this does not work if the data's size is ever modified, and also it might be a bit convoluted.