I have this wrapper function that is supposed to call the appropriate function on a large dataset based on the type of data it contains, like this:
void WrapperFunc( int iRealDataType, int iUseAsDataType )
{
// now call the right function based on both arguments
switch ( iRealDataType )
{
case FancyType1:
switch ( iUseAsDataType )
{
case CoolType1: DataAnalysisFunc_Fancy1_Cool1(); break;
// etc.
}
// etc.
}
}
So far, this was solved by having two nested switch statements and then calling one of the many many specialized functions for each existing combination of Real and UseAs data type. However as the number of defined types grows it is a nightmare to maintan the code base. So I decided to finally use templates. I mostly avoid them if I can, but this time they suit the problem well.
So now instead of DataAnalysisFunc_Fancy1_Cool1
i would like to call DataAnalysisFunc<FancyType1,CoolType1>
ang get rid of the hundreds of lines of switch statements, BUT i cannot use it like this, since FancyType1
is an enum, not the type (which is Fancy1
for example).
Just to clarify - I know this sounds like a stupid artificial example, but I tried to simplify the problem as much as possible to get to the core of it, instead of explaining the ton of details that would go into a much more concrete example.
EDIT: my data analysis functions are in reality CUDA kernels - this will probably rule out some possible solutions. Sorry for that.
Templates sound like the wrong solution. What you want is a lookup table.
typedef void (*DataAnalysisFunc)();
const DataAnalysisFunc DataAnalysisFunctions[NumFancyTypes][NumCoolTypes] = {
/*Fancy1*/ {
/*Cool1*/ &DataAnalysisFunc_Fancy1_Cool1,
/*Cool2*/ &DataAnalysisFunc_Fancy1_Cool2 }
/*Fancy2*/ {
/*Cool1*/ &DataAnalysisFunc_ImpossibleCombination, // can't happen, throw or something
/*Cool2*/ &DataAnalysisFunc_Fancy2_Cool2 }
};
void WrapperFunc(int realDataType, int useAsDataType) {
assert(realDataType >= 0 && realDataType < NumFancyTypes);
assert(useAsDataType >= 0 && useAsDataType < NumCoolTypes);
(*DataAnalysisFunctions[realDataType][useAsDataType])();
}
Now, if those DataAnalysisFuncs share a lot of code, templates might help you there, but not for dynamic dispatch.
BUT i cannot use it like this, since FancyType1 is an enum, not the type (which is Fancy1 for example)
You can convert enum
to type, just use one of metaprogramming basic tools:
Int2Type, it is used to replace run-time branches of if statements on the compile time dispatches.
It looks like:
template <int Number>
struct Int2Type
{
enum {value};
};
Int2Type - is treated as a type, using it and function overloading - you can replace if statements.
UPDATE: I added some example here, to make my answer more clear
1. Int2Type
// usage allows to implement dispatch in a compile time instead of branching statements in a run-time
template <int Val>
struct Int2Type
{
static const int val_= Val;
};
template <typename ItBegin, typename ItEnd>
void doSort(ItBegin it0, ItEnd it1, Int2Type<1>)
{
using namespace std;
// sort
cout << "Standart sorting algorithm was used. For iterators" << endl;
}
template <typename ItBegin, typename ItEnd>
void doSort(ItBegin it0, ItEnd it1, Int2Type<2>)
{
using namespace std;
// sort
cout << "Fast sorting algorithm was used. For pointers" << endl;
}
// based on the 3-rd dummy type parameter call will be dispatched to needed function
int arr[3];
MainTools::doSort(arr, arr + sizeof(arr) / sizeof(arr[0]), MainTools::Int2Type<1>());
vector<int> v(3);
MainTools::doSort(v.begin(), v.end(), MainTools::Int2Type<2>());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With