Reputation: 103
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
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