use*_*820 6 c++ templates boost instantiation
我一直在研究一个框架,以帮助功能模板即时.我有一堆函数,由整数值模板化以进行优化,需要在运行时进行实例化和选择.用法示例如下:
// 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);
Run Code Online (Sandbox Code Playgroud)
所以在那个例子中,我实例化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)
Run Code Online (Sandbox Code Playgroud)
在内核的循环中使用该语句是不可接受的性能损失.为了避免性能损失,我们用整数值(表示纹理索引)模拟内核,以便编译出上述条件语句.包含上述代码的内核将使用maskTextureIndex等于0-7进行实例化,因此我们在运行时有8个不同的内核可供选择.我们的一些内核使用多达3个纹理,我们允许每个纹理类型(例如float 1D,float 2D,float2 2D,int 3D等)具有索引0-7,这意味着我们必须实例化8*8*8 = 512个不同的内核编译出3个不同的条件语句,如上所述.根据使用纹理的内核,我使用原始问题中的代码来帮助实例化所有组合.
对于 C++03,我无法找到避免编写函数 typedef 的方法或使其更小的方法。使用 C++11 和 decltype,您可以像这样输入定义(假设您没有任何带有类型参数的模板):
typedef decltype(&MyFunction<0, 0, 0>) MyFunctionPointer;
Run Code Online (Sandbox Code Playgroud)
另一方面,您可以使为实例化的每个函数复制的一些代码变得不必要。在您的示例中,您声明了一个 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();
}
};
};
Run Code Online (Sandbox Code Playgroud)
您只需声明该结构一次并将其放入标头中的某个位置即可。它适用于具有三个相同类型参数的每个函数。以下是如何在示例中使用此结构体的函数。首先,声明mpl::vector用于提供实例化模板重载值的所有类型。然后创建一个结构体,该结构体提供一个function()返回重载的函数指针的方法。这是为您的示例函数定义的一个:
template<int a, int b, int c>
struct MyFunctionTypedef
{
static MyFunctionPointer function()
{
return &MyFunction<a, b, c>;
}
};
Run Code Online (Sandbox Code Playgroud)
of是实际传递给 的InnerStruct内容。仅用于将模板参数转发到内部结构。这些新类型的变量如下所示:FunctionTemplateCreatorCreateTemplatesFunctionTemplateCreatorCreateTemplates
CreateTemplates<FunctionTemplateCreator<int, MyFunctionTypedef, MyFunctionPointer, arrayOfTemplateInstantiations>::InnerStruct, templatesToCreate> unusedVariable;
Run Code Online (Sandbox Code Playgroud)
如果您开始使用 C++11,则可以使用function()中的方法。MyFunctionTypedefconstexpr