基于枚举调用适当的函数,但使用模板

时间:2013-12-19 14:06:13

标签: c++ templates

我有这个包装函数,应该根据它包含的数据类型调用大型数据集上的相应函数,如下所示:

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内核 - 这可能会排除一些可能的解决方案。对不起。

3 个答案:

答案 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在它们之间共享大量代码,那么使用模板可能是值得的,否则运行时调度可能是一个更好的解决方案。