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

Jar*_*edC 1 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
}
Run Code Online (Sandbox Code Playgroud)

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

template<int N>
class Widget
{
   .... member functions that use N ....
}
Run Code Online (Sandbox Code Playgroud)

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

Widget & GetWidget(int index);
Run Code Online (Sandbox Code Playgroud)

但是,在模板化Widget之后,每个小部件都有不同的类型,因此我无法再定义这样的函数.我考虑了不同的继承选项,但我不确定模板的性能增益是否会超过继承函数调用的成本.

那么,我的问题是:

我很确定我想要两全其美(编译时/运行时),这可能是不可能的.但是,有没有办法在编译时获得知道N的性能,但是仍然可以将Widgets作为相同的类型返回?

谢谢!

Ste*_*sop 8

这里的问题是,如果您将窗口小部件存储为相同的类型,那么从该存储中检索窗口小部件的代码(通过调用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; }
};
Run Code Online (Sandbox Code Playgroud)

当N已知时,优化器可能会发挥最佳作用,因为它可以最佳地展开循环,转换算法等等.但是通过虚拟呼叫,你可以看到一个很大的缺点,即没有任何一个呼叫可以被内联(我猜想虚拟呼叫比没有内联时的非虚拟呼叫更不可能被预测) ).内联未知N的收益可能超过了解N的收益,或者可能更少.尝试他们两个,看看.

对于更为牵强的努力,如果有相当少的常见案例,您甚至可以通过实现关键小部件功能看到改进,例如:

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;
};
Run Code Online (Sandbox Code Playgroud)

对所有情况"执行某些操作"但默认情况下可能是对常量上模板化的函数的调用,则默认值是与函数参数相同的代码而不是模板参数.或者它可以全部调用相同的函数(带有函数参数),但是在参数是常量的情况下依赖于编译器在优化之前内联调用,其结果与模板化的结果相同.

不是可以大规模维护的,并且通常不会像这样猜测优化器,但也许你知道常见的情况是什么,而编译器却没有.

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

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

但我认为来电者不知道,因为如果它确实那么你可能不会问...