c++函数与带整型形参的模板

C++ function vs template with an integer parameter?

本文关键字:形参 整型 函数 c++      更新时间:2023-10-16

阅读Wikibook优化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;
     }
}

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

您所考虑的调整只有在编译时参数已知时才有效。在你的引言中,有一个关于应用程序代码的假设,这是你在编写库时不能做的。

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

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_*()调用,如果参数是常量。

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

这取决于你想如何使用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

当你可以在编译时提供一个不会在运行时更改的参数时,你可以使用模板。模板总是在编译时求值,因此它们的输入和输出在程序运行之前就固定了!

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

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