c++ - 将 C++ 模板化对象存储为相同类型

标签 c++ performance templates

我有一个类是性能敏感代码路径的核心组件,因此我正在尝试尽可能地优化它。该类曾经是:

class Widget
{
    Widget(int n) : N(n) {}
    .... member functions that use the constant value N ....
    const int N;                // just initialized, will never change
}

构造函数的参数在编译时是已知的,所以我将此类更改为模板,以便 N 可以编译到函数中:

template<int N>
class Widget
{
   .... member functions that use N ....
}

我有另一个类有一个方法:

Widget & GetWidget(int index);

但是,在模板化 Widget 之后,每个 widget 都有不同的类型,所以我不能再这样定义函数了。我考虑了不同的继承选项,但我不确定模板带来的性能提升是否会超过继承函数调用的成本。

所以,我的问题是:

我很确定我想要两全其美(编译时/运行时),但这可能是不可能的。但是,有没有一种方法可以获得在编译时知道 N 的性能,但仍然能够返回相同类型的 Widget?

谢谢!

最佳答案

这里的问题是,如果您将小部件存储为相同类型,那么从该存储中检索小部件的代码(通过调用 GetWidget)不会在编译时知道 N[* ].调用构造函数的代码知道 N,但使用该对象的代码必须应对多种可能性。

由于性能影响(如果有的话)很可能是在使用小部件的代码中,而不是在创建小部件的代码中,因此您无法避免在关键代码中做某事取决于运行时信息。

可能对类模板中实现的函数的虚拟调用比对使用 N 的函数的非虚拟调用更快,但不知道其值:

class Widget {
  public:
    virtual ~Widget() {}
    virtual void function() = 0;
};

template <int N>
class WidgetImpl : public Widget {
  public:
    virtual void function() { use N; }
};

当 N 已知时,优化器可能会发挥最佳作用,因为它可以优化展开循环、转换算法等。但是对于虚拟调用,您首先会看到一个很大的缺点,那就是所有调用都不能内联(而且我猜想在没有内联时,虚拟调用比非虚拟调用更不容易被预测到).内联未知 N 的 yield 可能大于已知 N 的 yield ,也可能更少。试试看。

对于更牵强的努力,如果常见情况的数量相当少,您甚至可以通过将关键的小部件功能实现为类似以下内容来看到改进:

switch(n) {
    case 1: /* do something using 1 */; break;
    case 2: /* do the same thing using 2 */; break;
    default: /* do the same thing using n */; break;
};

在所有情况下都“做某事”,但默认情况下可能是调用以常量为模板的函数,然后默认情况下是使用函数参数而不是模板参数的相同代码。或者它可能都是对同一个函数的调用(带有函数参数),但在参数为常量的情况下,依靠编译器在优化之前内联调用,以获得与模板化相同的结果。

不可大规模维护,像这样事后猜测优化器通常不是一个好主意,但也许您知道常见情况是什么,而编译器却不知道。

[*] 如果调用代码在编译时确实知道 N 的值,那么您可以用这样的函数模板替换 GetWidget:

template <int N>
Widget<N> &getWidget(int index) {
    return static_cast<Widget<N> &>(whatever you have already);
}

但我假设调用者不知道,因为如果知道那么你可能不会问...

关于c++ - 将 C++ 模板化对象存储为相同类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4634696/

相关文章:

c++ - 在 i, k 中实际发生了什么; k &= i;

c++ - 链接 libncurses++ 和 libncurses 的问题

performance - 列表理解与 List.concat

c++ - 使用模板类型参数列表中的 TYPE

c++ - 如何使用来自可变模板参数的 typeid 填充 vector

wpf - 如何修复圆角按钮中边框和背景之间的空白区域?

c++ - 带有 QOpenGLWidget 的 Qt 5.5,核心配置文件中的隐形三角形

c++ - 如何在不引起递归的情况下使模板特化继承泛型基类?

mysql - 优化用于查找两个表之间匹配的MySQL查询

javascript - 如何在javascript之前加载图像