2014-06-02 3 views
2

Я пишу код для сотовых автоматов, и мне нужна эволюционная функция для вычисления состояния автоматов после шага времени. Я решил вызвать эту функцию evol, чтобы проверить ее, я создал элементарную функцию в C++. К сожалению, он не компилируется, поскольку компилятор не может понять, что мне нужно, чтобы он возвращал массив. Вот код:C++ - Возвращает многомерный массив из функции

#include <iostream> 
#include <cmath> 
#include <vector> 
#include <string> 

using namespace std; 

const int N = 51; // Size of the grid; two columns/rows are added at the beginning and the end of the array (no evolution of the CA on the boundaries) 

class Cell{ 
    //defining whats a cell here   
}; 

void showCA(Cell CA[N+2][N+2]){ 
    //function to print the CA grid in the terminal   
} 


Cell[N+2][N+2] evol(Cell CA[N+2][N+2]){ 
    return CA; 
} 

int main() 
{ 
    // Initialisation 
    cout << "Initialisation" << endl; 
    static Cell CA[N+2][N+2]; 
    // some code here to initialize properly the Cell array. 
    showCA(CA); 
    CA = evol(CA); 
    showCA(CA); 
    return 0; 
} 

Компилятор возвращает эту ошибку:

error: expected unqualified-id 
Cell[N+2][N+2] evol(Cell CA[N+2][N+2]){ 

Любая идея о том, как я должен это реализовать?

+1

используйте полуточку, чтобы исправить эту ошибку. Вы, вероятно, тоже хотите использовать векторы. –

+0

Что представляет собой 'N'? У вас есть ряд любопытных заявлений в вашем коде. Чего вы хотите достичь наконец? –

+4

Создайте класс для представления многомерного массива (возможно, как обертка для обеспечения 2D-адресации в 'std :: vector'). Верните экземпляр этого класса. –

ответ

3

Вы не можете вернуть массив из функций:

§ 8.3.5/8

Функции не должны иметь тип возвращаемого массива типа или функции, хотя они могут иметь тип возвращаемого типа указателя типа или ссылки на такие вещи.

Если вы хотите вернуть сырые массивы C-стиля из функций, вам необходимо использовать ссылку или указатель.Например, вот как это делается с помощью ссылки (вы можете сделать то же самое с помощью указателя, заменив & с *):

Cell (&evol(Cell (&CA)[N+2][N+2]))[N+2][N+2]; 

Однако, это очень неинтуитивными и трудно читать. Если ваш компилятор поддерживает новейший стандарт (C++ 11) тип возвращаемого значения может быть очищен с помощью завершающего типа возвращаемого:

auto evol(Cell (&CA)[N+2][N+2]) -> Cell(&)[N+2][N+2]; 

Но опять же, это, вероятно, еще труднее читать.


C++ 11 облегчает обработку массивов C-типа с контейнером std::array<>. Non-C++ 11 код должен использовать std::vector<>:

using Cells = std::array<std::array<Cell, N+2>, N+2>; 

Cells const& evol(Cells const& CA); 
+0

Если размер массива большой, то возврат std :: array может быть неэффективным или опасным (из-за этого вы догадаетесь, что переполнение стека). –

+0

@PeterSchneider Я сомневаюсь, что 'std :: array' будет иметь больше накладных расходов, чем обычный массив. И в любом случае размер для потенциального переполнения стека точно такой же при использовании массива vs 'std :: array', и в этом случае следует использовать' std :: vector'. – 0x499602D2

+0

Правда относительно переполнения; но возвращение std :: array просто копирует много байтов, не так ли (вместо возврата указателя или std :: vector с семантикой перемещения). –

0

Вы можете использовать

typedef std::vector<std::vector<Cell>> CellArray; 
CellArray Cells(N+2); // resize main dimension 
for (size_t i=0; i<N+2; i++) 
    Cells[i].resize(N+2); // resize all cells of main dimension 

провести свой массив ячеек, но также необходимо добавить конструктор копирования и оператор = в классе Cell

class Cell { 
public: 
    Cell() { ... default ctor code here ... } 
    Cell(const Cell &c) { *this = c; } 

    Cell &operator=(const Cell&c) 
    { 
     if (this != &c) 
     { 
      ... copy data from c members to this members here ... 
     } 
     return *this; 
    } 
}; 

Ваша функция эвол затем может возвращать CellArray :

CellArray evol(CellArray &c) 
{ 
    CellArray r; 
    ... do some calculations with c and r ... 
    return r; 
} 
+0

Вам не понадобится переезд ctor? И, возможно, чтобы избежать смешных сюрпризов для вашего преемника, задание на переезд? Все это звучит почти смехотворно. –

+0

@PeterSchneider Здесь нечего перемещать (RVO). Но если имеет смысл перемещать класс для перемещения и переносить назначаемый, он должен разрешать эти операции. – juanchopanza

0

после того, как вы указали переменную, используя синтаксис массива, как и у вас:

Cell CA[N+2][N+2]; 

Вы не можете назначить CA, чтобы быть чем-то другим. Вы можете назначать значения только его содержимому. Следовательно,

CA = evol(CA); 

неправ.

Вы можете сделать следующее:

Cell (*CA2)[N+2] = evol(CA); 
0

Так как число элементов, как представляется, фиксированной, я предлагаю вам использовать std::array контейнер:

const int N = 51; 
typedef std::array<std::array<Cell,N+2>, N+2> datatype; 

Вы можете использовать этот тип как тип возврата:

datatype Evol(const datatype& d); 

Вы можете обращаться к элементам так же, как если бы это был массив «C»:

datatype d; 
Cell c; 
d[10][20] = c; 
0

Я настоятельно рекомендую инкапсулировать массив в классе. Вы не можете вернуть массив, но вы можете вернуть объект, содержащий массив.

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