2014-12-26 3 views
0

Я ищу элегантный способ объявить 5-мерный массив в C++.5-мерная декларация вектора

Каждых вложенных векторы известны размерами, так что я начал делать:

std::vector<std::vector<std::vector<std::vector<double>>>> myDblVec; 

Тогда предполагая, я знаю, что всех размеры измерений:

myDblVec.resize(dim1); 
for (int d1 = 0; d1 != dim1; d1++) { 
    myDblVec[d1].resize[dim2]; 
    for (int d2 = 0; d2 != dim2; d2++) { 
     myDblVec[d1][d2].resize(dim3) 
     for (int d3 = 0; d3 != dim3; d3++) { 
      myDblVec[d1][d2][d3].resize(dim4); 
     } 
    } 
} 

Я ищу 1-вкладыш или что-то менее «тяжелое ', чтобы объявить этот массив.

+0

Я создал собственный класс для n-мерных массивов, которые инициализируются известными размерами для каждого вспомогательного массива. http://stackoverflow.com/questions/26665096/multidimensional-array-operator-overloading/26665964#26665964 – BWG

+0

a) имеет ли массив фиксированный размер? б) у вас есть только небольшой объем данных? Я спросил об этом, как вектор в векторе в ... просто чувствует ... ну, неправильно. –

+0

a) Нет, но с точки зрения теста да b) данные представляют изображение, поэтому могут быть довольно большими. Размер массива изменится, изменив разрешение изображения. – PinkTurtle

ответ

1

Если вы получаете размеры время выполнения, как

myDblVec = std::vector<std::vector<std::vector<std::vector<double>>>>(dim1, 
    std::vector<std::vector<std::vector<double>>>(dim2, 
     std::vector<std::vector<double>>(dim3, 
      std::vector<double>>(dim4, 0.0)))); 
+0

Ницца. Любые плюсы и минусы при использовании этих VS-массивов (в основном, с точки зрения производительности). Я знаю размер времени выполнения, но мой массив/вектор является частью определения класса, и я знаю только размеры после того, как мой класс инициализирован. Поэтому я должен повторно объявить его через какую-то функцию 'init'. – PinkTurtle

+0

@ Julien Arrays (включая 'std :: array') выделяются во время компиляции, поэтому размеры должны быть известны во время компиляции как константы времени компиляции. Они также не выделяются непосредственно из кучи, поэтому, если размеры достаточно велики, вы можете легко получить переполнение стека. –

1

Вы можете использовать std::array, предполагая, что размеры известны во время компиляции:

std::array<std::array<std::array<std::array<double, dim4>, dim3>, dim2>, dim1> myDblArray; 
+0

Ницца спасибо. – PinkTurtle

1

Если вы не слишком привязаны к pre-C++ 11, вы можете написать простой вариационный шаблон:

template <typename T, size_t... N> struct NestedArray;                                     

template <typename T, size_t N> struct NestedArray<T, N> {                                    
    using type = array<T, N>;                                           
}; 

template <typename T, size_t N, size_t... Rest> 
struct NestedArray<T, N, Rest...> { 
    using type = array<typename NestedArray<T, Rest...>::type, N>; 
}; 

Теперь вы можете определить ваш массив как NestedArray<double, dim1, dim2, dim3, dim4>::type.

+0

Я не ищу дополнительную сложность, но thx. Я новичок в C++, поэтому стараюсь использовать встроенную функциональную функцию (это имеет смысл :) – PinkTurtle

1

std::vector<T> принимает размер как аргумент первого конструктора. Вы можете воспользоваться этим и использовать somethign вдоль линий

make_vector_t<double, 5> myDblVec(init_vector<double, 5>(dim1, dim2, dim3, dim4, dim5)); 

Это будет rquire немного инфраструктуры для создания типов и инициализации элементов. Конечно, эта инфраструктура разумна прямо (хотя я ее не компилировал), в настоящее время я просто использую мобильное устройство, т. Е. Почти наверняка будет опечатка, но общий подход должен быть owrk):

template <typename T, int Dim> struct make_vector; 
template <typename T, int Dim> 
using make_vector_t = typename make_vector<T, Dim>::type; 
template <typename T> 
struct make_vector<T, 0> { using type = T; } 
template <typename T, int Dim> 
struct make_vector { using type = std::vector<make_vector_t<T, Dim-1>>; } 

template <typename T, int Dim, typename Arg, typename... Args> 
auto init_vector(Arg size, Args... sizes) -> make_vector_t<T, Dim-1> { 
    return make_vector_t<T, Dim>(size, init_vector<T, Dim-1>(sizes...); 
} 
0

хорошо ... vector<vector> действительно ли это хорошо? вы думаете о матрице, строки которой могут иметь независимую длину? Если ответ «нет», а затем рассмотреть идею, что все, что вам нужно, это обычный вектор, размер которого является произведением 5 размеров, и элементы которого расположены в

size_t at(size_t a, size_t b, size_t c, size_t d, size_t e, size_t A, size_t B, size_t C, size_t D, size_t E) 
{ return e+d*E+c*D*E+b*C*D*E+a*B*C*D*E; } 

(примечание: заглавные буквы размеры).

Вы можете легко обобщить это независимо от количества измерений с помощью varadics:

template<class... I> 
size_t at(size_t r, size_t R, size_t c, size_t C, I... i) 
{ return size_at(r*C+c,i...); } 

size_t at(size_t c, size_t C) 
{ return c; } 

И вы также можете встроить все это в повторяющийся класс

template<class T, size_t Rank> 
class grid 
{ 
    grid<T,Rank-1> m; size_t C; 
public: 
    template<class... I> 
    grid(size_t r, size_t c, I... i) :m(r*c,i...) :C(c) {} 

    template<class... I> 
    T& operator()(size_t r, size_t c, I... i) 
    { return m(r*C+c,i...); } 

    template<class... I> 
    const T& operator()(size_t r, size_t c, I... i) const 
    { return m(r*C+c,i...); } 
}; 

template<class T> 
class grid<T,1> 
{ 
    std::vector<T> m; 
public: 
    explicit grid(size_t n) :m(n) {} 

    T& operator()(size_t i) { return m[i]; } 
    const T& operator()(size_t i) const { return m[i]; } 
}; 

Вы можете просто объявить grid<5> a(3,2,4,5,3); и получить доступ к своим элементам как a(x,y,z,w,t); любой x в 0..2, y в 0..1, z в 0..3 w в 0..4 и t в 0..2;

0

Если вам тяжелая потребность в многомерных массивах, подумайте о перемещении материала, который должен иметь дело с ними, в отдельный исходный файл, который использует C вместо C++.Вы можете интерфейс довольно легко между языками, и выделение 5D массив динамических размеров в C так просто, как

double (*fiveDArray)[dim2][dim3][dim4][dim5] = malloc(dim1 * sizeof(*fiveDArray)); 

Использование практически такой же, как и с вложенными std::vector<> с, все, что вам нужно помнить, это вызов до free(), когда вы закончите свой массив. Если вам нужен нулевой инициализированный массив, замените malloc() на calloc(). В качестве дополнительного бонуса смежный характер многомерного массива C более приятен в кэшах процессора, чем использование std::vector<>, а индексирование происходит быстрее, поскольку есть только один указатель на погоню.

C++ не позволяет этого, потому что этот язык ограничивает размеры массива постоянными времени компиляции. С другой стороны, поднял это ограничение в стандарте C99, и даже позволяет динамические размеры массива в typedef:

void foo(size_t dim1, size_t dim2, size_t dim3, size_t dim4, size_t dim5) { 
    typedef double FourDSlice[dim2][dim3][dim4][dim5]; 
    FourDSlice *fiveDArray = malloc(dim1 * sizeof(*fiveDArray)); 

    ... 
} 

является совершенно законным C99, и невозможно сделать в C++.

Смежные вопросы