Ich habe an einem Framework gearbeitet, das bei der Erstellung von Funktionsvorlagen hilft. Ich habe eine Reihe von Funktionen, die zu Optimierungszwecken durch Integer-Werte templatiert werden, die zur Laufzeit instanziiert und ausgewählt werden müssen. Ein Anwendungsbeispiel ist die folgende:Benötigen Sie Hilfe Bereinigen von Vorlagen Instanziierungs-Framework
// 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);
Also in diesem Beispiel, ich bin Instanziieren MyFunction, die drei ganzzahlige Werte annimmt, mit jeder Kombination von { {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2}, {7, 0, 3, 4, 2} }
. Ich habe die Implementierung von CreateTemplates weggelassen, da es ziemlich lang ist, aber es wird mit Boost MPL for_each implementiert. Der obige Code wird für jede Funktion benötigt, mit der ich das machen möchte, und obwohl es kürzer ist als das Schreiben von 512 expliziten Instanziierungen, ist es immer noch ein bisschen lang.
Überraschenderweise ist der längste Code, der für jede Funktion geschrieben werden muss, mit der ich dies tun möchte, der Typdef des Funktionszeigers, da viele der Funktionen mehr als 10 Argumente benötigen. Gibt es eine Möglichkeit, diese Template-Instanziierungen in einem Array eines allgemeineren Typs zu speichern, indem Sie sie irgendwie umhüllen?
Aus Gründen der Argumentation können Sie davon ausgehen, dass die Template-Parameter immer ganzzahlige Werte wie im Beispiel sind, so dass die Signaturen der Template-Instanziierungen für eine gegebene Funktionsvorlage alle gleich sind. Die Funktionen, die instanziiert werden, befinden sich alle im globalen Namespace, niemals in Memberfunktionen (sie sind eigentlich CUDA-Kernel). Irgendwelche anderen Tipps, um dies zu reinigen, würden geschätzt werden.
Hinweis: Die Verwendung C++ 03
Edit: Ich wollte TarmoPikaro Frage nach adressieren, was ich versuche zu erreichen.
Ich arbeite mit einer Anwendung, wo bis zu 4 Aufgaben/Threads eine GPU teilen, um ihre Arbeit zu erledigen (gleiche Arbeit, andere Daten). Da einige unserer CUDA-Kernel Texturen verwenden, müssen wir zur Laufzeit dynamisch verfügbare Texturen ausgeben. Wir unterstützen die Legacy-CUDA-Rechenfunktionen, dh Texturobjekte können nicht als Funktionsargumente übergeben werden und müssen statische globale Variablen sein. Zu geben, Texturen CPU-Tasks/Threads dann, wir geben Textur Indizes und unsere CUDA Kerne haben Aussagen wie:
// (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)
diese Aussage in einer Schleife in einem Kernel zu haben ist eine nicht akzeptable Performance-Verlust. Um den Leistungsverlust zu vermeiden, modellieren wir den Kernel durch einen Integer-Wert (der den Texturindex darstellt), so dass die obige bedingte Anweisung kompiliert wird. Der Kernel, der den obigen Code enthält, wird mit maskTextureIndex gleich 0-7 instanziiert, sodass wir zur Laufzeit aus 8 verschiedenen Kernels auswählen können. Einige unserer Kernel verwenden bis zu 3 Texturen, und wir erlauben jedem Textur-Typ (zB float 1D, float 2D, float2 2D, int 3D usw.) Indizes 0-7 zu haben, was bedeutet, dass wir 8 * 8 * 8 = instanziieren müssen 512 verschiedene Kernel, um 3 verschiedene bedingte Anweisungen wie die obige zu kompilieren. Der Code in meiner ursprünglichen Frage wird pro Kernel verwendet, der Texturen verwendet, um alle Kombinationen zu instanziieren.
Leider ist es so, dass Programmiersprache selbst in irgendeiner Weise zugeschnitten werden kann, in der ursprünglich Autoren der Programmiersprache nicht gedacht haben. Ein solcher Missbrauch oder Missbrauch von Sprache ist für extreme Programmierer möglich, die denken, dass sie Gaia erreicht haben und tun können, was sie wollen, mit der Sprache. Leider wird es schwierig, diesen Code zu pflegen und weiterzuentwickeln, und es ist sehr wahrscheinlich, dass ein anderer Entwickler während der nächsten Iterationen höchstwahrscheinlich Ihre Lösung umschreiben wird. Vielleicht können Sie genauer spezifizieren, was Sie am Ende erreichen wollen? – TarmoPikaro
@TarmoPikaro Endlich haben Sie Ihre Frage angesprochen. Ich bin mir nicht sicher, ob es eine bessere Lösung gibt, ohne auf C++ 11 zu aktualisieren. Hoffe, jemand nimmt das als Herausforderung;). – user1777820