user3023621
user3023621

Reputation: 103

Passing a 3D array to a class (conversion problems)

I'm trying to write a class 'STFT' to perfom a short time FT. It calls the fftw3.h functions, which output a double*[2] array, and I want to create an array of these arrays. So I thought the following would be a suitable transform function (this is a stripped down version):

void STFT::Transform(double ***transform) {
//stuff
}

However, when I called it with say

transform[100][100][2]

I get the error message:

error: cannot convert double (*)[100][2]' to `double***

After looking around, I think I've found a solution using templates Storing C++ template function definitions in a .CPP file but I'm having trouble implementing it, mainly in figuring out where I put the general type indicator 'T'. My updated functions are:

STFT.hpp

class STFT {

public:
  template<int N>
  void Transform(double transform[][N][2]);
};

STFT.cpp

using namespace std;

template<int N>

void STFT::Transform(double transform[][N][2]) {
  cout << "IT WORKS" << endl;
}

and the function call is in main.cpp:

STFT stft;
double transform[100][100][2];

stft.Transform(transform);

However, this doesn't seem to work. The error message is:

undefined reference to `void STFT::Transform<100>(double (*) [100][2])

I imagine the problem lies in my naive implementation of templates. I've tried multiple different ways but I can't seem to get to a solution, if anyone can assist I'd be super grateful!

Upvotes: 0

Views: 76

Answers (1)

kebs
kebs

Reputation: 6707

You are tagging this as C++, but you are using C-style (and error prone) data storage. so use a "true" c++ solution: use the containers of the standard library.

Here, As far as I understand, you need a matrix of pair of values, so why not use for example:

typedef std::pair<double,double> myElements;
typedef std::vector<std::vector<myElements>> myContainer;
myContainer data; // instanciation
....
void STFT::Transform(myContainer& d) {
}

Populating the elements can be done this way:

for( size_t i=0; i<100; i++ )
{
    std::vector<myElements> new_vec;
    for( size_t j=0; j<100; j++ )
    {
        double val1 = ...;
        double val2 = ...;
        new_vec.push_back( std::make_pair(val1,val2) );
    }    
    data.push_back( new_vec );
} 

If you are concerned with performance, you can preallocate the size of the vector to the number of elements.

If std::pair isn't comfortable, you can use std::array that has the advantage of having a compile-time size:

 typedef std::array<double,2> myElements;

Then, instead of accessing with .first and .second, you just do:

data.at(i).at(j)[0] = ...;
data.at(i).at(j)[1] = ...;

or, if you are sure about your index values, and you dont want run-time bounds checking:

data[i][j][0] = ...;
data[i][j][1] = ...;

They are plenty of solutions, but please, forget about all these pointers and old-school memory allocation. I promise, I also used to program like this, I changed, and i am so glad that these containers exist, no more hours spend to debug either compile-time error messages , or run-time unexpected crashes.

And, no, if correctly used, there is (hardly) no timing overhead.

Upvotes: 3

Related Questions