I have a filter which is supposed to work on arbitrary tensors. For my case it is sufficient when the filter works on rank 1,2 and 3 tensors which are lists, matrices and 3d-matrices or volumes respectively. Additionally, the filter can be applied in each possible direction. For a list this is only one, for matrices exist 2 possible directions (namely X-direction and y-direction) and for volumes exist 3 possible direction.
Before I go into detail let me ask my question first: Is my layout of the filter ok or did I forgot something important which maybe gives me a hard time later? I’m not new to C++ templates, but it’s not that I feel like a fish in water. Is it possible to compress this layout further (maybe there’s a way around the dummy XDirection classes or a shorter Type2Type)?
The basic procedure of the filter is for every tensor-rank and for every direction the same. There is just a few lines of code, the function callKernel, which are different. To make the overloaded operator() call the right callKernel function is the only interesting part in the code below. Since partial specialization for templates does not work for class-methods, you can convert the template arguments into a real class-type and give this as dummy argument to callKernel.
The following code is they layout up to rank 2. It is compileable with g++ and can be tried.
template <class DataType, int Rank>
class Tensor { };
class XDirection;
class YDirection;
template <class TensorType, class Direction>
struct Type2Type {
typedef TensorType TT;
typedef Direction D;
};
template <class TensorType, class Direction>
struct Filter {
Filter(const TensorType &t){}
TensorType operator()(){
/* much code here */
callKernel(Type2Type<TensorType,Direction>());
/* more code */
TensorType result;
return result;
}
void callKernel(Type2Type<Tensor<double,1>, XDirection>) {}
void callKernel(Type2Type<Tensor<double,2>, XDirection>) {}
void callKernel(Type2Type<Tensor<double,2>, YDirection>) {}
};
int main(void) {
Tensor<double, 2> rank_two_tensor;
Filter<Tensor<double,2>,XDirection> f(rank_two_tensor);
f();
}
Let me add some important things: It is necessary that the filter-logic is in the operator() because what you see here is going used with the Intel Threading Building Blocks which require this structure. It is very important, that the callKernel is inlined. From everything I know, this should be the case.
Thanks in advance for any helpful and critical comment.
First, not bad for a first try on templates.
If you have a recent version of GCC you can simplify like this, there’s a better way to execute code conditionally on a type using
std::is_same<>. It will returntrueif the types are identical. It also makes your intent more explict.Edit: If you wish you can even move it to
op()to make sure the code is inlined.