【问题标题】:Need Help Cleaning Up Template Instantation Framework需要帮助清理模板实例化框架
【发布时间】:2016-03-27 23:34:34
【问题描述】:

我一直在研究一个帮助函数模板实例化的框架。我有一堆函数,出于优化目的,由整数值模板化,需要在运行时实例化和选择。使用示例如下:

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

在内核的循环中包含该语句是不可接受的性能损失。为了避免性能损失,我们通过整数值(表示纹理索引)对内核进行模板化,从而编译出上述条件语句。包含上述代码的内核将使用等于 0-7 的 maskTextureIndex 进行实例化,因此我们在运行时有 8 个不同的内核可供选择。我们的一些内核最多使用 3 个纹理,并且我们允许每种纹理类型(例如 float 1D、float 2D、float2 2D、int 3D 等)具有索引 0-7,这意味着我们必须实例化 8*8*8= 512 个不同的内核编译出 3 个不同的条件语句,如上面的一个。我的原始问题中的代码用于每个使用纹理的内核来帮助实例化所有组合。

【问题讨论】:

  • 不幸的是,编程语言本身可以以任何方式进行定制,这是编程语言的最初作者没有想到的。这种误用或滥用语言的极端程序员可能会认为他们已经达到了 Gaia 并且可以使用该语言为所欲为。不幸的是,这样的代码维护和进一步开发变得复杂,并且很有可能在下一次迭代期间另一个开发人员很可能会重写您的解决方案。也许您可以更详细地指定您最终想要实现的目标?
  • @TarmoPikaro 终于有时间解决你的问题了。如果不升级到 c++11,不确定是否有更好的解决方案。希望有人将其视为挑战;)。

标签: c++ templates boost instantiation


【解决方案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();
        }
    };
};

你只需要声明这个结构一次,然后把它放在某个地方的头文件中。它适用于具有三个相同类型参数的每个函数。这是在示例中将此结构用于函数的方法。首先,您声明所有用于提供值以实例化模板重载的 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,则可以将 MyFunctionTypedef 中的 function() 方法设置为 constexpr

【讨论】:

  • 我给了你赏金花时间看它,因为我找不到更好的答案。感谢您的帮助!看来是时候升级到 c++11了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-18
  • 2021-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
  • 1970-01-01
相关资源
最近更新 更多