Greg Berchin
Greg Berchin

Reputation: 13

C++ 3D Matrix Using References

Request for a sanity check ...

I am storing a 3D matrix in a 1D array as follows:

double * myVector = new double[NCHANNELS*NROWS*NCOLUMNS];

I want to be able to access myVector using [channel][row][column] syntax, so I am creating a C++ reference:

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] = myVector;

Have I used the proper syntax here, i.e., will

my3dMatrix[channel][row][column] 

return

*(myVector + channel*NROWS*NCOLUMNS + row*NCOLUMNS + column)?

Thanks.

Upvotes: 1

Views: 144

Answers (1)

HolyBlackCat
HolyBlackCat

Reputation: 96906

Yes, you can do it. But your reference initializator is missing type cast and dereference operator, it will not even compile. It should be:

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] =
    *(double (*)[NCHANNELS][NROWS][NCOLUMNS])myVector;

If you're using C++11/14, you can use this fancy syntax instead:

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] =
    *(decltype(&my3dMatrix))myVector;


Also, if you like to use these new C++-style casts, you can use this:

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] =
    *reinterpret_cast<double (*)[NCHANNELS][NROWS][NCOLUMNS]>(myVector);

or C++11 version:

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] =
    *reinterpret_cast<decltype(&my3dMatrix)>(myVector);

Syntax explanation

When you initialize a reference, you can only use initializator of a certain type. This type must match the type reference refers to.

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] = expression;

In this case you need expression to be double [NCHANNELS][NROWS][NCOLUMNS].

myVector can't be used here because it's a pointer to array and my3dMatrix is a reference to an array. Ok, then we need to deference operator.

But *myVector does not work either. It's double [NCHANNELS*NROWS*NCOLUMNS] but we need double [NCHANNELS][NROWS][NCOLUMNS]. You want to tell the compiler than he should assume that myVector is pointing to another type before dereferencing it. In these cases you need a type cast.

The way you write them is (type)expression and reinterpret_cast<type>(expression).

(First one came from C language. Second one is one of the modern C++ casts. There are 4 of them, each one have a specific purpose. C-style cast does the same and can be used instead of all 4. C++-style ones are used by some guys because they think that these casts are more readable. I personally consider them too bulky and use old one.)

So, here is your reference initialization:

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] =
     *       (double (*)[NCHANNELS][NROWS][NCOLUMNS])  myVector;
     ^       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^
dereference             C-style type cast             expression

Compiler trusts you and assumes that myVector is a double (*)[NCHANNELS][NROWS][NCOLUMNS]. After dereferncing it becomes double [NCHANNELS][NROWS][NCOLUMNS] - the type you need.


Now, about that decltype trick. (It was added in 2011, so old compilers don't support it.) decltype(expression) is replaced by the compiler with the type of expression. For example, decltype(1) means int. decltype(my3dMatrix) means double [NCHANNELS][NROWS][NCOLUMNS]. But you need another type, because you can't cast pointer to 1D array to 3D array. You can cast it to pointer to 3D array instead. When you want address of something, you use &. So, you need decltype(&my3dMatrix). You can assume it means (double (&*)[NCHANNELS][NROWS][NCOLUMNS]), but there is no such thing as pointer to reference, so it becomes just (double (*)[NCHANNELS][NROWS][NCOLUMNS]).

double (& my3dMatrix)[NCHANNELS][NROWS][NCOLUMNS] =
     *       (decltype(&my3dMatrix))  myVector;
     ^       ^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^
dereference     C-style type cast    expression

I hope you understood it.

Upvotes: 3

Related Questions