Reputation: 97
I want to use a templated structure in order to mimic an array of doubles in 4 dimensions, the maximum size for each dimension is know in compilation time. Therefore, I think that using templates structure will give a chance to gain performance. You can find my attempt for the implementation bellow. The code compiles unless that I attempt to instantiate one structure. I don't understand what is the problem with the code bellow, suggestions will be very appreciated.
Even more, I want to do two improvements if possible: 1) I want to be capable of use data of type float and of type double 2) Will be fancy to have some kind of overloaded operator that enables to assign values to the records of data in a similar way as T(N,L,M,J)=val in place of having to use T.assign(N,L, M,J,value). Again, suggestions will be very appreciated.
My aim is to fill the data in T_4D as fast as possible.
#include <iostream>
#include <cstring> // for memset
using namespace std;
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10,double *data=NULL>
struct T_4D {
enum {SIZE = dim_N*dim_L*dim_M*dim_J };
enum {LEN1 = dim_N };
enum {LEN2 = dim_L };
enum {LEN3 = dim_M };
enum {LEN4 = dim_J };
static void create()
{
data=(double *)malloc(SIZE*sizeof(double));
memset(data, 0.0, SIZE*sizeof(*data));
}
static size_t multi_index(const size_t N) {
return N;
}
static size_t multi_index(const size_t N,const size_t L) {
return L*dim_N + N;
}
static size_t multi_index(const size_t N,const size_t L, const size_t M) {
return (M*dim_L + L)*dim_N + N;
}
static size_t multi_index(const size_t N,const size_t L, const size_t M,const size_t J) {
return ((J*dim_M + M)*dim_L + L)*dim_N + N;
}
double operator()(size_t N,size_t L, size_t M, size_t J){
return data[multi_index(N,L,M,J)];
}
static void assign(size_t N,size_t L, size_t M, size_t J,double value){
data[multi_index(N,L,M,J)]=value;
}
};
int main()
{
double *instance;
T_4D<3,3,3,10,instance> T;
T.create();
return 0;
}
The compilation errors are:
./main.cpp: In function ‘int main()’:
./main.cpp:49:17: error: the value of ‘instance’ is not usable in a constant expression
T_4D<3,3,3,10,instance> T;
^
./main.cpp:48:11: note: ‘instance’ was not declared ‘constexpr’
double *instance;
^
./main.cpp:49:25: error: ‘instance’ is not a valid template argument because ‘instance’ is a variable, not the address of a variable
T_4D<3,3,3,10,instance> T;
^
./main.cpp:50:5: error: request for member ‘create’ in ‘T’, which is of non-class type ‘int’
T.create();
^
Makefile:197: recipe for target 'obj/main.o' failed
make: *** [obj/main.o] Error 1
Upvotes: 1
Views: 296
Reputation: 2837
If all of your dimensions are known at compile time, there is no need for you to allocate dynamic memory. Simply use:
std::aligned_storage_t<sizeof( T ) * SIZE, alignof( T )> data;
You don't even need to initialize anything since you're working with POD types. If you want to zero the memory out, just use this:
for ( std::size_t i = 0; i < SIZE; ++i )
*( reinterpret_cast<T*>( &data ) + i ) = 0;
This will be the most efficient implementation, since we use static contiguous memory. You'll have to implement proper indexing, but that's not too difficult.
Actually, just use T data[ SIZE ];
or std::array<T, SIZE> data
.
Also, remove the double*
template parameter, these cannot be changed, so it can't be used for your data.
Upvotes: 1
Reputation: 206567
Using double* data = NULL
as a template parameter does not seem right. You can use a double*
as a template parameter but you can't assign to it as you are doing with:
data=(double *)malloc(SIZE*sizeof(double));
You can remove that as a template parameter and make it a member variable of the class.
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10>
struct T_4D {
double* data;
...
and then allocate memory for it in the constructor instead of in the static
member function.
T_4D() : data(new double[SIZE])
{
memset(data, 0.0, SIZE*sizeof(*data));
}
Remember to follow The Rule of Three and The Rule of Five since you are allocating memory from the heap.
Then, main
can simply be:
int main()
{
T_4D<3,3,3,10> T;
return 0;
}
Upvotes: 1