2016-03-27 29 views
6

İşlev şablonu oturumları konusunda yardımcı olmak için bir çerçeve üzerinde çalışıyorum. Çalışma zamanında başlatılması ve seçilmesi gereken, optimizasyon amaçları için tamsayı değerine ayarlanmış bir dizi işlevim var. { {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2} } her kombinasyonu ile, 3 tamsayı değerleri alırYardıma mı ihtiyacınız var? Şablon Örnekleme Çerçevesini Temizleme

// 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); 

Yani bu örnekte, ben başlatmasını ediyorum MyFunction, A kullanım örneği şudur. Oldukça uzun olduğu için, CreateTemplates uygulamasının kullanımını ihmal ettim, ancak MPL for_each desteğini kullanarak uygulandı. Yukarıdaki kod, bunu yapmak istediğim her işlev için gereklidir ve 512 açık ifadeleri yazmaktan daha kısa olsa da, hala biraz uzun.

Şaşırtıcı bir şekilde, bunu yapmak istediğim her işlev için yazılması gereken en uzun kod, işlevlerin çoğunun 10'dan fazla argüman alması nedeniyle işlev işaretçisinin yazım hatasıdır. Bu şablon örneklemelerini, bir şekilde daha fazla türdeki bir dizide saklamak için bir yolu var mı?

Bağımsız değişken için, şablon parametrelerinin örnekte olduğu gibi her zaman tamsayı değerleri olduğunu varsayabiliriz, böylece şablon örneklemlerinin imzaları belirli bir işlev şablonu için aynıdır. Anlatılan işlevlerin tümü genel ad alanındadır, hiçbir zaman üye işlevleri değildir (aslında CUDA çekirdekleridir). Bunu temizlemek için başka ipuçları takdir edilecektir.

Not: ++ c Kullanılması 03

Düzenleme: Ben başarmak istediğim şey hakkında TarmoPikaro sorusunu ele almak istedik.

İşlerini yapmak için en fazla 4 görev/iş parçacığının bir GPU'yu paylaşacağı bir uygulama ile çalışıyorum (aynı iş, farklı veriler). Bazı CUDA çekirdeklerimiz dokuları kullandığından, çalışma zamanında mevcut dokuları dinamik olarak dağıtmamız gerekir. Eski CUDA bilgi işlem yeteneklerini desteklememize bağlıyız. Bu, doku nesnelerini işlev argümanları olarak geçirilemez ve statik global değişkenler olmalıdır. Daha sonra CPU görevleri/dişlerine dokuları dışarı vermek için, doku indeksleri dışarı vermek ve CUDA çekirdekleri gibi ifadeler var: kabul edilemez bir performans kaybı bir çekirdekte bir döngü içinde bu ifadeyi edilir olması

// (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) 

. Performans kaybını önlemek için, yukarıdaki koşullu ifadenin derleneceği şekilde, çekirdeği tamsayı değeriyle (doku dizinini temsil ederek) şablonlandırıyoruz. Yukarıdaki kodu içeren çekirdek, 0-7'ye eşit olan maskTextureIndex ile başlatılacak, bu nedenle çalışma zamanında seçmek için 8 farklı çekirdek var. Çekirdeklerimizden bazıları 3 dokuya kadar kullanır ve her doku tipine (örn. Yüzer 1D, yüzer 2B, yüzer 2B2, int 3D, vb.) 0-7 arası indekslere sahip olmalarına izin veririz, yani 8 * 8 * 8 = Yukarıdaki gibi 3 farklı koşullu ifadeyi derlemek için 512 farklı çekirdek. Orijinal kombinasyonumdaki kod, tüm kombinasyonları oluşturmaya yardımcı olmak için dokular kullanan çekirdek başına kullanılır.

+0

Ne yazık ki, programlama dilinin kendisi, başlangıçta programlama dilinin yazarlarının düşünmediği herhangi bir şekilde uyarlanabilir. Bu tür suistimal veya istismar edici bir dil, Gaia'ya ulaştıklarını düşünen ve dil ile istedikleri her şeyi yapabileceğine inanan aşırı programcılar için mümkündür. Ne yazık ki böyle bir kod, daha fazla korumak ve geliştirmek için karmaşık hale gelir ve bir sonraki geliştirmeler sırasında başka bir geliştirici muhtemelen çözümünüzü yeniden yazabilir. Sonunda ne elde etmek istediğinizi daha ayrıntılı olarak belirtebilir misiniz? – TarmoPikaro

+0

@TarmoPikaro Sonunda sorunuzu ele almak için vardık. C++ 11'e yükseltmeden daha iyi bir çözüm olduğundan emin değilsiniz. Birisi bunu bir meydan okuma olarak kabul ediyor;). – user1777820

cevap

1

C++ 03 ile, typedef işlevini veya daha küçük hale getirmenin bir yolunu yazmaktan kaçınmanın bir yolunu bulamadım. C++ 11 ve bunu böyle typedef olabilir decltype (herhangi tip parametrelerle şablonları yok varsayarak) ile: Öte yandan

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

, size etrafta kopya kod bazı yapabilirsiniz Gereksizleştirdiğiniz her fonksiyon. Örneğinizde, bir MyFunctionTemplateCreator yapısını bildirdiniz. Bu yapı, bu örnekleme için işlev işaretçisinin değerini sağlamak için çok daha küçük bir yapıya ihtiyaç duyması için değiştirilebilir.

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(); 
     } 
    }; 
}; 

Yalnızca bu yapı bir kez beyan ve yerde bir başlık koymak zorunda: Burada yapının daha genel bir versiyonudur. Üç özdeş tip parametresi olan her işlev için çalışacaktır. Örneğinizdeki işlev için bu yapıyı nasıl kullanacağınız aşağıda açıklanmıştır. Önce, şablon aşırı yüklemelerini başlatmak için değerleri sağlamak için kullanılan tüm mpl::vector türlerini bildirirsiniz. Ardından, aşırı yüklenmenin işlev işaretçisini döndüren bir function() yöntemi sağlayan bir yapı oluşturursunuz.

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

FunctionTemplateCreator ait InnerStruct aslında CreateTemplates yazdıklarıyla geçirilir edilir: İşte örnek fonksiyonu için tanımlanmış biridir. FunctionTemplateCreator sadece şablon parametrelerini iç yapıya iletmeye yarar. İşte CreateTemplates değişken bu yeni türleri ile nasıl görüneceğini geçerli: MyFunctionTypedef yılında

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

C++ 11 function() yöntemi kullanmaya başlarsam constexpr yapılmış olabilir.

+0

Size bakmak için zaman ayırdığınız için teşekkür ettim ve daha iyi bir cevap bulamadım. Yardım için teşekkürler! C++ 11'e yükseltmenin vakti gelmiş gibi görünüyor. – user1777820

İlgili konular