2

I am writing a code for Cellular Automata and I need an evolution function to calculate the state of the automata after a time step. I choose to call this function evol, to test it I created an elementary function in C++. Unfortunately it does not compile since the compiler cannot understand that I need it to return an array. Here is the code :

#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;
} 

The compiler returns this error :

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

Any idea on how I should implement this ?

8
  • 1
    use a semi colon to fix that error. You probably want to use vectors as well. Commented Jun 2, 2014 at 20:07
  • What does N actually represent? You have a number of curious statements in your code. What do you want to achieve finally? Commented Jun 2, 2014 at 20:07
  • 4
    Create a class to represent a multi-dimensional array (probably as a wrapper to provide 2D addressing into a std::vector). Return an instance of that class. Commented Jun 2, 2014 at 20:07
  • The standard way for the past decades has been to provide a target array as an argument to evol, which would return nothing or perhaps bool, indicating success. Probably the caller would have two arrays which would swap roles as source and target after each evolution. Commented Jun 2, 2014 at 20:31
  • Your syntax for declaring a function returning an array is incorrect. Use Cell evol(Cell CA[N+2][N+2])[N+2][N+2] rather than Cell[N+2][N+2] evol(Cell CA[N+2][N+2]) to get a more helpful error message. Commented Jun 2, 2014 at 21:03

5 Answers 5

3

You cannot return arrays from functions:

§ 8.3.5/8

Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things.

If you are wishing to return raw, C-style arrays from functions, then you have to use a reference or pointer. For example, here's how it is done using a reference (you can do the same using a pointer by replacing & with *):

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

However, this is very unintuitive and hard to read. If your compiler supports the latest standard (C++11) the return type can be cleaned up using a trailing return type:

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

But again, this is probably still harder to read.


C++11 facilitates the handling of C-style arrays with the container std::array<>. Non-C++11 code should use std::vector<>:

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

Cells const& evol(Cells const& CA);
Sign up to request clarification or add additional context in comments.

12 Comments

If the array size is large returning a std::array may be inefficient or dangerous (because of, you guess it, stack overflow).
@PeterSchneider I doubt std::array will have any more overhead that a regular array. And in any case the size for a potential stack overflow is exactly the same when using an array vs std::array, and one should use a std::vector in that case.
True with respect to overflow; but returning a std::array just copies lots of bytes around, doesn't it (as opposed to returning a pointer or a std::vector with move semantics).
Additionally, if you return a reference to a C array you better don't have it on the stack.
@PeterSchneider There is no problem with returning the array by value. The copy will be elided. If it is not elided for whatever reason (exotic C++ implementation/platform, pre-standards compiler etc.) then one can start thinking of clever ways to fix that problem.
|
0

You can use

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

to hold your cell array, but you also need to add a copy constructor and operator= in Cell class

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;
    }
};

Your evol function then can return a CellArray:

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

2 Comments

Wouldn't you also need a move ctor? And perhaps, to avoid funny surprises for your successor, a move assignment? This all sounds almost ridiculously overkill.
@PeterSchneider There's nothing to be moved here (RVO). But if it makes sense for a class to be move copyable and move assignable, it should allow these operations.
0

once you have declared a variable using the array syntax like you have:

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

you cannot assign CA to be something else. You can only assign values to its contents. Hence,

CA = evol(CA);

is wrong.

You can do the following:

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

Comments

0

As the number of elements seems to be fixed, I suggest you use the std::array container:

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

You can then use this type as a return type:

datatype Evol( const datatype& d );

You can access elements just as if it was a "C" array:

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

Comments

0

I would strongly suggest encapsulate your array into a class. You cannot return an array, but you can return an object that contains an array.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.