2016-03-27 8 views
6

私は、関数テンプレートのインスタンシエーションを支援するフレームワークに取り組んできました。私は、実行時にインスタンス化して選択する必要がある、最適化のために整数値でテンプレート化されたたくさんの関数を持っています。 { {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2} }のすべての組み合わせで、3つの整数値をとるテンプレートインスタント化フレームワークのクリーンアップの助けが必要

// 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を、:使用例は次のとおりです。私はかなり長いので、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) 

を容認できないパフォーマンスの損失です。パフォーマンスの低下を避けるために、上記の条件文がコンパイルされるようにカーネルに整数値(テクスチャインデックスを表す)をテンプレート化します。上記のコードを含むカーネルは、0-7のmaskTextureIndexでインスタンス化されるため、実行時に8つの異なるカーネルを選択できます。私たちのカーネルの中には、最大3つのテクスチャを使用するものがあります。各テクスチャタイプ(float 1D、float 2D、float2 2D、int 3Dなど)はインデックス0-7を持ちます。つまり、8 * 8 * 8 =上記のような3つの異なる条件文をコンパイルするために512の異なるカーネル。私の元の質問のコードは、テクスチャを使用するカーネルごとに使用され、すべての組み合わせをインスタンス化するのに役立ちます。

+0

残念ながら、プログラミング言語そのものは、もともとプログラミング言語の作者が考えなかったように、どのような方法でも調整できます。このような悪用や悪用の言葉は、ガイアに到達したと思う極端なプログラマーが可能であり、言葉を使いたいことを何でもすることができます。残念なことに、このようなコードは複雑になり、さらに発展し、次の反復では他の開発者があなたのソリューションを書き換える可能性が非常に高いです。最終的に達成したいことをより詳細に指定することができますか? – TarmoPikaro

+0

@TarmoPikaro最後にあなたの質問に対処しました。 C++ 11にアップグレードすることなく、より良いソリューションがあるかどうかはわかりません。誰かが挑戦としてそれを取ることを望む;)。 – user1777820

答えて

1

C++ 03では、関数typedefを書く方法やそれを小さくする方法を見つけることができませんでした。 C++ 11とdecltypeを使用すると、(あなたが型パラメータを持つ任意のテンプレートを持っていないと仮定して)このようにそれをtypedefの可能性:一方

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

を、あなたはあなたが周りのコピーのコードの一部を行うことができますインスタンス化するすべての関数は不要です。あなたの例では、構造体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(); 
     } 
    }; 
}; 

あなたは一度だけこれが構造宣言し、どこかのヘッダーでそれを配置する必要があります。これは、3つの同一タイプのパラメータを持つすべての関数に対して機能します。あなたの例の関数にこの構造体を使用する方法は次のとおりです。最初に、テンプレートのオーバーロードをインスタンス化するために値を提供するために使用されるすべてのmpl::vectorタイプを宣言します。次に、オーバーロードの関数ポインタを返すfunction()メソッドを提供する構造体を作成します。ここではあなたの例の機能のために定義されたものです。

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

FunctionTemplateCreatorInnerStructは、実際にCreateTemplatesに渡されるものです。 FunctionTemplateCreatorはテンプレートパラメータを内部構造体に転送する役割しか果たしません。ここでCreateTemplates変数は、これらの新しいタイプでどのように見えるかです:

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

あなたがC++ 11の使用を開始する場合はMyFunctionTypedeffunction()方法がconstexpr作ることができます。

+0

私はあなたにそれを見る時間をとってくれた恩恵を与えました。そして、より良い答えを見つけることができなかったからです。助けてくれてありがとう! C++ 11にアップグレードする時間がかかるようです。 – user1777820

関連する問題