草庐IT

c++ - 需要帮助清理模板实例化框架

coder 2024-02-05 原文

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

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

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

最佳答案

对于 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++ - 需要帮助清理模板实例化框架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36253928/

有关c++ - 需要帮助清理模板实例化框架的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  6. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

    我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

  7. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  8. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

  9. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  10. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

随机推荐