in a finite element code, I’ve a data structure to manipulate the value of a field (coordinates, temperature, ...) at a point. This structure is basic and looks like this:
class point_data
{
public:
void allocate(int ldim); // allocation of data;
const double* get_data() const { return data; }
void set_data(const double* ldata); // for example
…
protected:
double* data;
…
}
I then use objects of type point_data* to evaluate expressions, for example to impose boundary conditions. To be concrete, if x, y are the coordinate fields, and I impose a temperature T equal to sin(y) on a boundary defined by x == 0, then I have a “sin” operator object, whose evaluate method takes a point_data* argument (in fact a point_data**) and return a point_data* containing the result. Same thing for my “==” object, which also takes a point_data** argument (array of two point_data* this time) and return the result.
As my structure for supporting data of global fields is already template, and since it is this structure that creates point_data objects, I wanted templatized the class point_data. Then, I tried:
class abstract_point_data
{
protected:
int dim;
public:
abstract_point_data() : dim{0} { ; }
virtual ~abstract_point_data() { ; }
const int& get_dim() const { return dim; }
void set_dim(int ldim) { dim = ldim; }
virtual void allocate(int ldim=0) = 0;
// get_data ??? set_data ???
};
template <typename T>
class point_data : public abstract_point_data
{
public:
point_data() : my_data{0}, allocated{false} { ; }
virtual ~point_data() { delete_data(); }
virtual void set_data(const T* ldata);
virtual const T* get_data() const { return my_data; }
virtual void allocate(int ldim);
protected:
T* my_data;
bool allocated;
void delete_data() { if ( allocated ) { delete [] my_data; allocated = false; } }
};
template <typename T>
void point_data<T>::allocate(int ldim)
{
dim = ldim;
delete_data();
my_data = new T[ldim];
allocated = true;
}
template <typename T>
void point_data<T>::set_data(const T* ldata)
{
for (int i=0; i<dim; i++)
my_data[i] = ldata[i];
}
with the main:
abstract_point_data* mp = new point_data<double>;
mp->allocate(1);
double val = 1.0;
( (point_data<double>*) mp)->set_data(&val);
delete mp;
This way, the evaluate method of my operator objects can have an abstract_point_data** as an argument. In can also create the result object, because I know for example that a sine provide a double, or by cloning one of the arguments. But, that’s it. In general, I don’t know the type of my arguments in the evaluate function and therefore I can’t (of course) access the getters and setters. I’ve tried things like CRTP, decltype(auto), or even stupid stuff like std::tuple<bool,int,double> my_types; + decltype(std::get<get_my_index()>(my_types)) to store the type of my template “in” abstract_point_data, but nope, the C++ rules seem inviolable.
Can anyone give me an idea or reference to help me redefine (if possible) an acceptable templatized data structure? Thanks in advance.
In addition : the reason of using abstract_point_data was (if it worked) to only deal with abstract_point_data objects (as method arguments, in containers...), instead of dealing with point_data<int>, point_data<double>, ... (but maybe I missed something).