【问题标题】:C++ metaprogramming with templates versus inlining使用模板与内联的 C++ 元编程
【发布时间】:2010-03-04 14:48:47
【问题描述】:

是否值得编写如下代码来复制数组元素:

#include <iostream>
using namespace std;


template<int START, int N> 
struct Repeat { 
  static void copy (int * x, int * y) {
   x[START+N-1] = y[START+N-1];
   Repeat<START, N-1>::copy(x,y);
  }
};

template<int START> 
struct Repeat<START, 0> { 
  static void copy (int * x, int * y) {
   x[START] = y[START];
  }
};



int main () {


   int a[10];
   int b[10];

             // initialize
   for (int i=0; i<=9; i++) {
     b[i] = 113 + i;
     a[i] = 0;
   }

            // do the copy (starting at 2, 4 elements)
  Repeat<2,4>::copy(a,b);

             // show
   for (int i=0; i<=9; i++) {
   cout << a[i] << endl;
   }

} // () 

还是使用内联函数更好?

第一个缺点是您不能在模板中使用变量。

【问题讨论】:

  • 你应该只使用std::copy。您几乎可以肯定 that 利用一些元编程技术将 int 数组之间的复制转发到 memmove。
  • 天啊,我宁愿花 10 辈子的编程序言,也不愿再花时间看 C++ 编译时元编程 :(。如果你要复制一些东西,你就必须复制它,你无法逃脱通过认为你可以在编译时执行它只是因为你认为你可以识别将被复制的变量
  • @Hassan:根据数据类型和对齐方式,不同的复制策略可能是合适的,并且可能会显着加快操作速度。它不是“只是一个副本”。 (但正如@UncleBens 所说,std::copy 已经这样做了)
  • 这很有帮助。这是我见过的唯一解决方案,您可以在其中指定在代码中展开多少。我用 Repeat 查看了 GCC 中的程序集输出,它展开了 100 次。尽管许多人声称,循环展开仍然对性能有用。如果您知道自己在做什么,很容易击败memcpystd::copy。但展开在其他情况下更有用,例如 z[i] = x[i] + y[i]。

标签: c++ templates metaprogramming


【解决方案1】:

这不是更好。首先,它不是真正的编译时间,因为您在这里进行函数调用。如果幸运的话,编译器会将这些内联并最终生成一个循环,您可以用更少的代码(或仅使用std::copy)编写自己的循环。

【讨论】:

  • 这不是真的。递归是编译时的,这里没有运行时递归。每个函数属于不同的类,只是不同的函数。不过,对于 Java 来说,这会是真的!
  • @PierreBdr,确实每次都涉及不同的功能。但这些是在运行时完成的函数调用,其效果就好像您会以递归方式调用相同的函数(与 true 编译时递归ala' static int const value = Class&lt;N-1&gt;::value + 1; 相反)。唯一的区别是可以在编译时评估结束条件。但是等价循环的条件也可以。
  • @PierreBdr,我已经删除了声明这是一个递归函数的部分,因为我同意你的说法,这是误导性的。
  • 我阅读了生成的汇编代码,看起来像: copy_first: mov ... mov ... call copy_second copy_second: mov ... mov ... call copy_third copy_third: mov ... mov .... 代码将执行相同的操作,只是删除调用!
  • @JohannesSchaub-litb,我查看了 GCC 中 OPs 问题中代码的程序集输出。它根据需要展开循环。这是我见过的自动展开的最佳解决方案。
【解决方案2】:

一般规则:对编译时已知的事物使用模板,对运行时已知的事物使用内联。如果您在编译时不知道数组的大小,请不要使用模板。

【讨论】:

    【解决方案3】:

    你不应该这样做。模板是为了不同的目的而发明的,而不是为了计算,尽管你可以做到。一是不能使用变量,二是模板在编译时会产生大量未使用的结构,三是:使用for (int i = start; i &lt;= end; i++) b[i] = a[i];

    【讨论】:

    • 是的,模板是为不同的目的而发明的,但你无法想象有多少书籍和电子墨水用于第二次非预期用途!
    • 是的,不要对无法证实的模板发表声明。
    【解决方案4】:

    这样更好,因为您可以自己控制和强制执行循环展开。

    编译器可以根据优化选项展开循环...

    使用copy 进行复制几乎是最好的这一事实并不是一个好的通用答案,因为循环展开可以在内部进行的任何计算中完成...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-06
      • 1970-01-01
      • 2011-04-11
      • 2015-12-03
      • 2018-11-11
      • 1970-01-01
      • 2013-05-02
      • 1970-01-01
      相关资源
      最近更新 更多