8

阅读 Wikibook Optimizing C++,在本段中有以下建议:

如果整数值在应用程序代码中是常量,但在库代码中是变量,则将其设为模板参数。

所以如果我有一个像

void myfunction(int param)
{
     switch(param)
     {
          case 1:
              do_something_1();
          break;

          case 2:
              do_something_2();
          break; 

          ...

          case 100:                 // 100 is taken as example
              do_something_100();
          break;
     }
}

换成下面这样方便吗?

template<int param> void myfunction()
{
     switch(param)
     {
          case 1:
              do_something_1();
          break;

          case 2:
              do_something_2();
          break; 

          ...

          case 100:                 // 100 is taken as example
              do_something_100();
          break;
     }
}

还是完全没有必要?你能解释一下原因吗?

4

3 回答 3

6

只有在编译时知道参数时,您想到的调整才有效。在您的报价中,有一个关于您在编写库时无法做出的应用程序代码的假设。

如果您的应用程序代码中的函数调用曾经是

const int x = 3;
myfunction(1);
myfunction(2);
myfunction(x);
//etc...

它们可以重写如下。

const int x = 3;
myfunction<1>();
myfunction<2>();
myfunction<x>();
//etc...

但如果x是一个变量,这是不可能的:

int x = ...;      // unknown at compile-time!
myfunction<x>();  // will fail to compile!

如上所述,在某些情况下,您不应该在编写库时对应用程序做出假设。有时你想要或需要做。让我们考虑一下您希望应用程序使用常量但您不想强制它这样做的情况。

您想针对将使用常量仍允许使用变量的情况进行优化。为此,我建议两种选择:

  • 做两种选择,一种带有模板参数,另一种带有函数参数。

  • 内联函数,因此在编译应用程序代码时,编译器可以看到函数的定义,如果参数为常量,则可以将其优化为单个do_something_*()调用。

请注意,这两个选项都需要将函数的定义暴露给应用程序的代码。我更喜欢使用第二个选项。

于 2013-02-27T09:34:10.560 回答
3

这取决于你想如何使用myfunction. 例如,您的模板化函数不能与在运行时声明的变量一起使用:

int dosomethingmaybe = 1;
dosomethingmaybe += 2;
myfunction< dosomethingmaybe >(); // <--- Error, you cannot instantiate a template with a non-constant variable
myfunction( dosomethingmaybe ); // <--- Will call `do_something_3();`, according to your code

当您可以在编译时提供不会在运行时更改的参数时,您可以使用模板。模板总是在编译时进行评估,因此它们的输入和输出在程序运行之前就已经固定了

如果您知道有人可以提前修复输入并期望某个功能输出,请制作模板版本。否则,常规函数运行时版本就可以了。

于 2013-02-27T09:34:36.837 回答
1

我怀疑您是否真的会在这里看到实际情况下的性能优势。如果调用是内联的,那么这两种方法之间没有区别——只要参数在编译时是已知的(它必须是),一个体面的编译器将在这两种情况下删除不必要的开关。您会看到差异的唯一情况是如果没有发生内联 - 在这种情况下,模板化方法将允许删除开关,而另一种则不会。但是,无论如何,在这种情况下,函数调用开销可能会使切换成本相形见绌。

于 2013-02-27T09:43:25.350 回答