Suppose that I have a vector length calculation function, which has an additional inc
parameter (this tells the distance between neighboring elements). A simple implementation would be:
float calcLength(const float *v, int size, int inc) {
float l = 0;
for (int i=0; i<size*inc; i += inc) {
l += v[i]*v[i];
}
return sqrt(l);
}
Now, calcLength
can be called with two kind of inc
parameters: when inc
is known at compile-time, and when it is not. I'd like to have an optimized calcLength
version for common compile-time values of inc
(like 1).
So, I'd have something like this:
template <int C>
struct Constant {
static constexpr int value() {
return C;
}
};
struct Var {
int v;
constexpr Var(int p_v) : v(p_v) { }
constexpr int value() const {
return v;
}
};
template <typename INC>
float calcLength(const float *v, int size, INC inc) {
float l = 0;
for (int i=0; i<size*inc.value(); i += inc.value()) {
l += v[i]*v[i];
}
return sqrt(l);
}
}
So, this can be used:
calcLength(v, size, Constant<1>()); // inc is a compile-time constant 1 here, calcLength can be vectorized
or
int inc = <some_value>;
calcLength(v, size, Var(inc)); // inc is a non-compile-time constant here, less possibilities of compiler optimization
My question is, would it be possible somehow to keep the original interface, and put Constant
/Var
in automatically, depending on the type (compile-time constant or not) of inc
?
calcLength(v, size, 1); // this should end up calcLength(v, size, Constant<1>());
calcLength(v, size, inc); // this should end up calcLength(v, size, Var(int));
Note: this is a simple example. In my actual problem, I have several functions like calcLength
, and they are large, I don't want the compiler to inline them.
Note2: I'm open to different approaches as well. Basically, I'd like to have a solution, which fulfills these:
- the algorithm is specified once (most likely in a template function)
- if I specify
1
asinc
, a special function instantiated, and the code most likely gets vectorized - if
inc
is not a compile-time constant, a general function is called - otherwise (non-1 compile-time constant): doesn't matter which function is called