我一直致力于一个框架来帮助实现函数模板即时功能。我有一堆函数,由整数值模板化以进行优化,需要在运行时进行实例化和选择。用法示例如下:
// 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 :(得分:1)
使用C ++ 03,我无法找到避免编写函数typedef或使其变小的方法。使用C ++ 11和decltype,你可以像这样输入dede(假设你没有任何带有类型参数的模板):
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();
}
};
};
您只需要声明此结构一次并将其放在某个标题中。它适用于具有三个相同类型参数的每个函数。以下是如何在示例中将此结构用于函数。首先,声明用于提供值的所有mpl::vector
类型,以实例化模板重载。然后创建一个提供function()
方法的结构,该方法返回重载的函数指针。这是为您的示例函数定义的一个:
template<int a, int b, int c>
struct MyFunctionTypedef
{
static MyFunctionPointer function()
{
return &MyFunction<a, b, c>;
}
};
InnerStruct
的{{1}}实际上是传递给FunctionTemplateCreator
的。 CreateTemplates
仅用于将模板参数转发到内部结构。以下是FunctionTemplateCreator
变量对这些新类型的影响:
CreateTemplates
如果您开始使用C ++ 11,CreateTemplates<FunctionTemplateCreator<int, MyFunctionTypedef, MyFunctionPointer, arrayOfTemplateInstantiations>::InnerStruct, templatesToCreate> unusedVariable;
中的function()
方法可以MyFunctionTypedef
。{/ p>