将正常函数更改为模板将产生任何正/负差异

Changing a normal function to template will make any positive/negative difference?

本文关键字:任何正 常函数 函数      更新时间:2023-10-16

我有一个包装函数(模板化)Outer()和核心功能函数Inner()

namespace N
{
  A* Inner (void *p, int value, const int ID);
  template<typename T>
  A* Outer (T *p, const int ID)  // ID is a compile time constant
  {
    return Inner (p, p->value, ID);
  }
}

用法:

A *px = Outer(new X(3), 12345);
A *py = Outer(new Y(4), 987);

我设法将编译时间常数作为ID传递。因此,我正在考虑将Outer()原型更改为

template<int ID, typename T>
A* Outer (T *p)
{
  return Inner (p, p->value, ID);
}

将用作

A *pz = Outer<333>(new Z(5));

想知道的是,新方法是否对代码/性能级别有任何影响?是否会对内联产生任何影响

编辑:ID肯定在编译时,并且出现了几个Outer()实例(这就是为什么了解inline也很重要)。

首先,由于ID应该是int,因此模板应该是

template<int ID, typename T>
A* Outer (T *p)
...

不过,接下来,就起起伏伏而言,这在一定程度上取决于你的使用情况,但这里有一些确定的事实:

性能

真的不应该有任何明显的区别。由于将为ID的每个值创建一个新函数,因此它的执行应该就像您刚刚用本地ID常量声明了自己的单独函数一样。因此,模板版本可能会更快,因为在函数调用时不会复制值,但正如我所说,它可能不够重要,不足以破坏交易。

用法

这两种形式实际上并不等同。由于函数定义是在编译时根据ID的值定义的,因此只能使用编译时常量(这似乎是您所期望的)。在原始版本中,用户可以编写

int i = 10;
Outer<Z>(new Z(5), i);

虽然i是一个变量,但它作为常数值复制到ID

在模板版本中,他们不能写

int i = 10;
Outer<i, Z>(new Z(5));

由于编译器为ID的每个值生成不同的函数,因此在运行时之前不知道值的情况下,它不可能在编译时创建函数

因此,您的原始版本要灵活得多,而您提出的更改则非常严格。我认为大多数人都希望以原始的方式使用该函数,这样他们就不会被迫使用编译时间常数。因此,除非出于某种原因,真的需要ID值作为编译时常数,否则我会坚持使用原始值。

编译代码

对于编译后的代码,您的二进制文件将更大(假设您对ID的至少两个不同值使用该函数)。这是因为程序中使用的ID的每个不同值都会创建一个新函数。因此,如果你期望使用许多不同的值,二进制文件中的膨胀可能会成为的一个问题

内衬

这是一个我没有明确答案的问题。我猜如果内联受到影响,它可能会受到参数T而不是ID的影响。

无。函数是一个模板,因此必须内联,而像这样的常量折叠是内联函数时最常见的优化之一。这表明,如果你有一个现代编译器,它绝对不会有任何区别。

假设你做得正确(代码具有相同的功能),那么引入的唯一惩罚就是编译时间的增加,因为编译模板比编译正常函数需要更长的时间。

你可以说"我有超高速的计算机,编译需要1/2秒",但对于大项目来说,这很重要。

这将取决于编译器和函数的使用方式。在实践中,如果你已经进行了优化不同之处在于调用语法。但是如果您有性能问题,请分析并查看问题所在来自。