【问题标题】:loop unrolling and metaprogramming(TMP)?循环展开和元编程(TMP)?
【发布时间】:2017-11-23 09:26:36
【问题描述】:

在阅读wikipedia' article-Template metaprogramming[编译时代码优化]时:

template <int length>
Vector<length>& Vector<length>::operator+=(const Vector<length>& rhs) 
{
    for (int i = 0; i < length; ++i)
        value[i] += rhs.value[i];
    return *this;
}

当编译器实例化上面定义的函数模板时,可能会产生如下代码:[需要引用]

template <>
Vector<2>& Vector<2>::operator+=(const Vector<2>& rhs) 
{
    value[0] += rhs.value[0];
    value[1] += rhs.value[1];
    return *this;
}

编译器的优化器应该能够展开 for 循环,因为模板参数长度在编译时是一个常数。

但是,请小心,因为这可能会导致代码膨胀,因为将为您实例化的每个“N”(向量大小)生成单独的展开代码。

但是,我在编写 TMP 代码时了解到,应该避免循环,因为它是运行时的,并且使用模板递归是一种替代。

我在谷歌上搜索编辑并找到手动解压的this question。答案还鼓励使用递归。

那么,我应该依赖编译时代码优化,它能够在编译时使用编译时确定长度(循环结束)来展开 for 循环,还是一直使用递归?

我认为来自维基百科的文章鼓励我们依靠展开。是不是我理解错了?

【问题讨论】:

  • 你有没有考虑过使用std::integer_sequence 不一定需要使用递归?
  • 您对非展开循环有什么顾虑?你对它们进行了基准测试吗? 需要展开的循环并不多

标签: c++ templates metaprogramming


【解决方案1】:

循环展开与模板无关(至少在一般情况下)。当大小已知时,编译器可以展开循环(他们也可以展开非静态有界循环,但这要困难得多)。

如果你使用模板递归,那只意味着你可以控制循环展开的方式。

无论如何,不​​要尝试过早优化...滚动循环不太可能是您的运行时成本问题。让编译器展开至少是免费的,而自己做有点痛苦和容易出错,而且不确定结果是否值得。

【讨论】:

  • 即使您手动展开循环,也没有什么可以阻止编译器查看它,确定缓存压力更重要,然后重新滚动您的循环返回
  • @Caleth 不知道循环重滚!谢谢你的信息,每天都能学到东西。
【解决方案2】:

根据我的经验,循环展开可以达到一定的长度。我猜如果代码变得太大,这会对缓存产生负面影响并导致性能不佳

【讨论】:

    猜你喜欢
    • 2016-12-03
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 2012-11-18
    • 1970-01-01
    相关资源
    最近更新 更多