I am writing numerical simulation code in C ++. In this simulation, there are some things that are “local” with a floating point value at each point of the two-dimensional grid, and others that are “global” with only one global floating point value.
Besides this difference, the two types of objects behave the same, so I would like to have an array containing both types of objects. However, since this is a numerical simulation, I need to do it in such a way that (a) avoids the overhead of invoking virtual functions as much as possible and (b) allows the compiler to maximize the use of optimization - and, in particular, allows the compiler to perform automatic SIMD vectorization, where it perhaps.
Currently, I find that I am writing code like this (which, I understand, will not actually work as intended):
class Base {};
class Local: public Base {
public:
float data[size];
};
class Global: public Base {
public:
float data;
};
void doStuff(Local a, Local b) {
for (int i; i<size; ++i) {
a.data[i] += b.data[i];
}
}
void doStuff(Local a, Global b) {
for (int i; i<size; ++i) {
a.data[i] += b.data;
}
}
void doStuff(Global a, Local b) {
for (int i; i<size; ++i) {
a.data += b.data[i];
}
}
void doStuff(Global a, Global b) {
a.data += b.data*size;
}
My code is a bit more complicated than this - the array is two-dimensional, and there are several doStufftypes that have three rather than two arguments, so I have to write eight specializations for each.
The reason this does not work is because argument types are doStuffnot known at compile time. I want to make an array Base *and call doStufffor its two members. Then I want the right specialization to be doStuffinvoked for the specific types of its arguments. (It doesn't matter if a doStuffvirtual method call is involved - I just want to avoid them in the inner loop.)
, , () operator[], , () SIMD doStuff(Local, Local) doStuff(Local, Global), doStuff(Global, Global). , , .
. , , , , doStuff(Base, Base), , . (, gcc , doStuff(Global, Global).)
, , , , , , .
class Base {
virtual float &operator[](int) = 0;
};
class Local: public Base {
float data[size];
public:
float &operator[](int i) {
return data[i];
}
};
class Global: public Base {
float data;
public:
float &operator[](int i) {
return data;
}
};
void doStuff(Base a, Base b) {
for (int i; i<size; ++i) {
a[i] += b[i];
}
}
, . ( , , . , !)
CRTP, , , , , - doStuff.