2013-12-19 38 views
3

我有一個應該基於其包含的數據類型來調用大型數據集的相應功能這個包裝的功能,如:調用相應功能基於一個枚舉,但使用模板

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

「iRealDataType」和「iUseAsDataType」的每個組合是一個有效的組合還是隻是一個子集? – SirGuy

+0

這是一個子集,但如果組合是有效的,則在別處處理。 – PeterK

+0

是你傳遞給上述函數變量或常量的值,還是有時候? – Yakk

回答

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共享大量代碼,模板可能會幫助您,但不能用於動態分派。

+0

啊,我的簡化反彈了一下。我想我不能這樣做,因爲這些功能實際上是CUDA內核。感謝您的提示,但! – PeterK

+0

@PeterK他們是否開始CUDA內核阻止他們成爲函數指針?如果是這樣,你不能把它們包裝在一個常規的功能,並使用它? – SirGuy

+0

說實話,我不確定如果函數指針指向CUDA內核是一個問題,從來沒有嘗試過。另一方面,這是爲了簡化代碼,而不是使其更加模糊。然而,我會研究這一點,看看是否有可能。 – PeterK

2

但我不能這樣使用它,因爲FancyType1是一個枚舉,而不是 類型(這是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>()); 
+0

'Int2Type'已經在標準中作爲'std :: integral_constant'。 – Simple

+0

@簡單 - 謝謝你的信息。 –

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; 

注:
塞巴斯蒂安雷德爾指出,使用模板大概是隻有當DataAnalasysFunc在它們之間共享很多代碼時才值得,否則運行時調度可能是更好的解決方案。