0
votes

I'm trying to create a program that can read some data from 2 files. The first file is the header, that describe the data structure (dimensions, data type, extents, etc...), and the second is the raw data.

To handle different data type at runtime, I created a templated class that will be used as a container for the data. Depending on the data type read in the header, I will create a specialized class of the container to store the data.

However, now I'm facing another issue. How can I create a dynamic multidimensional array at runtime ?

I first thought doing it the old fashion way, and put a pointer into the storage class, and creating some loops ( = to the dimensionality) to create a new array (new array[size]). But I don't think it's a very clean way of doing it.

I also thought about stacking std::vector, but I don't know the dimensionnality before runtime.

Then I considered using boost to create a multi_array, and using resize() to update the extent of my array at runtime, but it is required to know the dimension when creating the array (multi_array< type, dim > variable). As I want to be able to access this in all my class (for future processing, etc...), I don't see how to put that in my class, as I will only know the dimensionnality at runtime. Is it possible to create a base pointer of multi_array in my class, and declare it later (when I will know the dimension needed) ?

Or is there another way to do this ? My final goal is to create a multidimensional array at runtime, that I can access in all my class.

Thank you.

Edit: Most of the topics I read about it are for fixed dimensional array, with a variating size. But in my case, dimension also varies.

Update: Your answer inspired me an idea Hugues. I already have a templated class to read the data, but for now it only takes as parameter, the data type. I'm thinking adding the dimensionnality to it and create a class like that: storageClass< data_type, data_dimension > myStorage(filename, data_extent, data_endian, data_encoding);

This way, I can also template the dimensionnality of the data, and create a multidimensionnal array (using boost for example). I will let you know if it worked. Thank you.

Update 2: Apparently it's not possible cause templates expect constant expression. I cannot pass the variable 'dimension' (even if it's a fixed value in this case, but it's not define at compile-time). So I guess my best option is to create a variadic getter in the custom storage class, and return the corresponding value. The problem is that a variadic method involve to parse the arguments, and as this is a method that will be frequently called, it's not optimal.

1

1 Answers

0
votes

It is likely necessary to create a custom class. One idea is to have it contain two main members m_dims and m_data:

#include <vector>
#include <cassert>

using std::size_t;

template<typename T> class MultiArray {
 public:
    MultiArray(const std::vector<int>& dims)
        : m_dims(dims), m_data(product(m_dims)) { }
    const std::vector<int>& dims() const { return m_dims; }
    const T& operator[](const std::vector<int>& indices) const {
        return m_data[index(indices)];
    }
    T& operator[](const std::vector<int>& indices) {
        return m_data[index(indices)];
    }
 private:
    std::vector<int> m_dims;
    std::vector<T> m_data;
    static size_t product(const std::vector<int>& dims) {
        size_t result = 1;
        for (size_t i = 0; i<dims.size(); ++i) result *= size_t(dims[i]);
        return result;
    }
    size_t index(const std::vector<int>& indices) const {
        size_t v = 0;
        for (size_t i = 0; i<m_dims.size(); ++i) {
            assert(indices[i]>=0 && indices[i]<m_dims[i]);
            if (i) v *= size_t(m_dims[i]);
            v += size_t(indices[i]);
        }
        return v;
    }
};

int main() {
    MultiArray<float> ar{std::vector<int>{2, 3}};
    ar[std::vector<int>{0, 0}] = 1.f;
    ar[std::vector<int>{0, 1}] = 2.f;
    ar[std::vector<int>{0, 2}] = 3.f;
    ar[std::vector<int>{1, 0}] = 4.f;
    ar[std::vector<int>{1, 1}] = 5.f;
    ar[std::vector<int>{1, 2}] = 6.f;
}

See code in http://coliru.stacked-crooked.com/a/92e597d4769f9cad