我有这个包装函数,应该根据它包含的数据类型调用大型数据集上的相应函数,如下所示:
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.
}
}
到目前为止,这是通过使用两个嵌套的switch语句然后为Real和UseAs数据类型的每个现有组合调用许多专用函数之一来解决的。但是,随着定义类型数量的增加,维护代码库是一场噩梦。所以我决定最终使用模板。如果可以的话,我主要是避开它们,但这次它们很适合这个问题。
所以现在而不是DataAnalysisFunc_Fancy1_Cool1
我想调用DataAnalysisFunc<FancyType1,CoolType1>
来摆脱数百行的switch语句,但我不能这样使用它,因为FancyType1
是一个枚举,而不是类型(例如Fancy1
)。
只是为了澄清 - 我知道这听起来像是一个愚蠢的人为例子,但我试图尽可能地简化问题以获得它的核心,而不是解释大量的细节将会更多具体的例子。
编辑:我的数据分析功能实际上是CUDA内核 - 这可能会排除一些可能的解决方案。对不起。
答案 0 :(得分:4)
模板听起来像是错误的解决方案。你想要的是一个查找表。
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])();
}
现在,如果这些DataAnalysisFuncs共享大量代码,模板可能会帮助您,但不能用于动态调度。
答案 1 :(得分:2)
但我不能这样使用它,因为FancyType1是枚举,而不是 type(例如Fancy1)
您可以将enum
转换为类型,只需使用元编程基本工具之一:
Int2Type ,它用于在编译时调度中替换if语句的运行时分支。
它看起来像:
template <int Number>
struct Int2Type
{
enum {value};
};
Int2Type - 被视为类型,使用它和函数重载 - 您可以替换if语句。
更新: 我在这里添加了一些例子,以使我的回答更清晰
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>());
答案 2 :(得分:1)
您正在寻找类型调度。我发现Boost.MPL最容易做到这一点。
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/at.hpp>
struct DispatchChecker
{
int iRealDataType, iUseAsDataType;
template <class T>
void operator()(T) const
{
static const int iCurrentReal = boost::mpl::at_c<T, 0>::type::value;
static const int iCurrentUseAs = boost::mpl::at_c<T, 1>::type::value;
if(iRealDataType == iCurrentReal &&
iUseAsDataType == iCurrentUseAs)
DataAnalysisFunc<iCurrentReal,iCurrentUseAs>();
}
};
typedef /*mpl sequence of all valid types*/ valid_types;
boost::mpl::for_each<valid_types>(DispatchChecker{iRealDataType,iUseAsDataType});
boost::mpl::for_each
接受编译时序列,并在序列的每个元素上实例化并运行仿函数。在这种情况下,仿函数会检查编译参数是否与运行时参数匹配,并在匹配时调用相应的DataAnalysisFunc
。
至于如何获得valid_types
,最简单的方法是在这样的序列中写出每个有效对:
typedef boost::mpl::vector<
boost::mpl::vector_c<int, 0, 0>,
boost::mpl::vector_c<int, 2, 0>,
boost::mpl::vector_c<int, 1, 1>,
boost::mpl::vector_c<int, 0, 2>,
boost::mpl::vector_c<int, 1, 2>
> valid_types;
注意:
正如Sebastian Redl所指出的,如果DataAnalasysFunc
在它们之间共享大量代码,那么使用模板可能是值得的,否则运行时调度可能是一个更好的解决方案。