2016-03-27 47 views
6

我一直在研究一個框架來幫助功能模板的即時通訊。我有一堆函數,用整數值爲模板進行優化,需要在運行時進行實例化和選擇。甲用法例子如下:需要幫助清理模板即時框架

// Function to instantiate templates of. 
template<int a, int b, int c> void MyFunction(float, double){}; 

// List of values to substitute into each template parameter. 
typedef mpl::vector_c< int, 7, 0, 3, 4, 2> valuesToInstantiate; 
int numberOfValuesPerParameter = size<valuesToInstantiate>::type::value; 

// Function pointer type. Must define type for array to hold template instantiations. 
typedef void (*MyFunctionPointer)(float, double); 

// Array to hold template instantiations. 
// Accessed at runtime to get proper instantiation. 
MyFunctionPointer arrayOfTemplateInstantiations[numberOfValuesPerParameter*numberOfValuesPerParameter*numberOfValuesPerParameter]; 

// Passed to template instantiation framework. 
// AddTemplate member function will be called once per template value combo (3 int values). 
// templateIndex indicates where to store the instantation in the array. 
// templateSequence contains the template value combo (3 int values). 
template<int templateIndex, typename templateSequence> 
struct MyFunctionTemplateCreator 
{ 
    static void AddTemplate(void) 
    { 
     // Store template instantiation in array. 
     arrayOfTemplateInstantiations[templateIndex] = MyFunction 
     < 
     mpl::at<templateSequence, mpl::int_<0> >::type::value, 
     mpl::at<templateSequence, mpl::int_<1> >::type::value, 
     mpl::at<templateSequence, mpl::int_<2> >::type::value 
     >; 
    } 
}; 

// List of lists where each inner list contains values to instantiate 
// for the corresponding template parameter. E.g. each value in the first 
// inner list will be passed into the first template parameter of MyFunction 
typedef mpl::vector< valuesToInstantiate, valuesToInstantiate, valuesToInstantiate > templatesToCreate; 

// Call template instantation framework to instantiate templates. 
CreateTemplates<MyFunctionTemplateCreator, templatesToCreate> unusedVariable; 

// Call proper template instantation at runtime...using index 5 arbitrarily for example. 
arrayOfTemplateInstantiations[5](1.5, 2.0); 

所以在這例子中,我實例MyFunction的,這需要3的整數值,與{ {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2} }每個組合。我省略了CreateTemplates的實現,因爲它很長,但它使用boost MPL for_each實現。上面的代碼對於我想要做的每個函數都是必需的,雖然它比寫出512個顯式實例要短,但它仍然有點長。令人驚訝的是,我想要爲每個函數編寫的最長代碼是函數指針的typedef,因爲許多函數需要10+個參數。有沒有辦法將這些模板實例存儲在一個更通用類型的數組中?

爲了論證的緣故,您可以假定模板參數總是像整個示例一樣的整數值,這樣模板實例化的簽名對於給定的函數模板都是相同的。實例化的函數全部在全局名稱空間中,而不是成員函數(它們實際上是CUDA內核)。任何其他技巧來清理這一點,將不勝感激。

注意:使用C++ 03

編輯:我想解決TarmoPikaro的什麼我試圖完成的問題。

我正在與一個應用程序,其中最多4個任務/線程將共享一個GPU來完成他們的工作(相同的工作,不同的數據)。由於我們的一些CUDA內核使用紋理,因此我們需要在運行時動態提供可用的紋理。我們堅持支持傳統的CUDA計算功能,這意味着紋理對象不能作爲函數參數傳遞,並且必須是靜態全局變量。爲了讓出紋理CPU的任務/線程,然後,我們給出了質地指數和我們的CUDA內核有這樣的語句:

// (variables t_int_2d_N are texture objects) 
if (maskTextureIndex == 0) 
    maskValue = tex2D(t_int_2d_0, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 1) 
    maskValue = tex2D(t_int_2d_1, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 2) 
    maskValue = tex2D(t_int_2d_2, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 3) 
    maskValue = tex2D(t_int_2d_3, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 4) 
    maskValue = tex2D(t_int_2d_4, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 5) 
    maskValue = tex2D(t_int_2d_5, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 6) 
    maskValue = tex2D(t_int_2d_6, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 
else if (maskTextureIndex == 7) 
    maskValue = tex2D(t_int_2d_7, (float(p) + 0.5f)*maskScale.x + maskShift.x, (float(q) + 0.5f)*maskScale.y + maskShift.y) 

有在內核中的一個循環語句是不可接受的性能損失。爲了避免性能損失,我們通過整數值(表示紋理索引)對內核進行模板化,以便將上述條件語句編譯出來。包含上述代碼的內核將被maskTextureIndex等於0-7的實例化,所以我們有8個不同的內核可以在運行時選擇。我們的一些內核最多使用3個紋理,並且我們允許每個紋理類型(例如float 1D,float 2D,float2 2D,int 3D等)具有索引0-7,這意味着我們必須實例化8 * 8 * 8 = 512個不同的內核來編譯出3個不同的條件語句,如上所述。我使用原始問題中的代碼,每個使用紋理的內核幫助實例化所有組合。

+0

不幸的是,編程語言本身可以以任何方式進行定製,其中編程語言的原作者並沒有想過。這種濫用或濫用語言對於認爲他們已經到達蓋亞並可以隨意使用該語言的任何極端程序員是可能的。不幸的是,這樣的代碼變得越來越複雜,難以進一步維護和開發,而且很有可能在下一次迭代中另一位開發人員很可能會重寫您的解決方案。也許你可以更詳細地指定你想在最後達到什麼目的? – TarmoPikaro

+0

@TarmoPikaro終於開始解決你的問題。不確定沒有升級到c + + 11有更好的解決方案。希望有人把這當作挑戰;)。 – user1777820

回答

1

使用C++ 03,我一直無法找到一種避免寫入函數typedef或者使其更小的方法。隨着C++ 11和decltype,你可以的typedef像這樣(假設你沒有與類型參數的任何模板):

typedef decltype(&MyFunction<0, 0, 0>) MyFunctionPointer; 

在另一方面,你可以做一些你身邊複製的代碼你實例化的每個函數都是不必要的。在你的例子中,你已經聲明瞭一個struct MyFunctionTemplateCreator。該結構可以被改變,以便它只需要一個更小的結構來爲該實例化提供函數指針的值。下面是該結構的更寬泛的版本:

template< 
    typename Arg, 
    template <Arg, Arg, Arg> class TemplateClass, 
    typename Func, 
    Func* instantiationArray> 
struct FunctionTemplateCreator 
{ 
    template< 
     int templateIndex, 
     typename templateSequence> 
    struct InnerStruct 
    { 
     static void AddTemplate(void) 
     { 
      instantiationArray[templateIndex] = TemplateClass 
       < 
       mpl::at<templateSequence, mpl::int_<0> >::type::value, 
       mpl::at<templateSequence, mpl::int_<1> >::type::value, 
       mpl::at<templateSequence, mpl::int_<2> >::type::value 
       >::function(); 
     } 
    }; 
}; 

你只需要聲明這個結構體一次,把它放在一個頭的地方。它適用於每個具有三個相同類型參數的函數。這裏是你如何在你的例子中使用這個結構的函數。首先聲明用於提供值來實例化模板重載的所有mpl::vector類型。然後創建一個結構,該結構提供了一個function()方法,該方法返回重載的函數指針。這是一個爲您例如函數定義:

template<int a, int b, int c> 
struct MyFunctionTypedef 
{ 
    static MyFunctionPointer function() 
    { 
     return &MyFunction<a, b, c>; 
    } 
}; 

FunctionTemplateCreatorInnerStruct是實際傳遞到CreateTemplatesFunctionTemplateCreator僅用於將模板參數轉發給內部結構。這裏是CreateTemplates變量將會是什麼樣這些新類型:

CreateTemplates<FunctionTemplateCreator<int, MyFunctionTypedef, MyFunctionPointer, arrayOfTemplateInstantiations>::InnerStruct, templatesToCreate> unusedVariable; 

如果開始使用C++ 11的function()方法MyFunctionTypedef可以作出constexpr

+0

我給你的時間來看看它的賞金,因爲我找不到更好的答案。感謝您的幫助!看起來可能是升級到C++ 11的時候了。 – user1777820