c++ - CRTP vs 过载和最终

标签 c++ c++11 crtp

我经常使用CRTP从基类调用派生类函数。它的优点是不会产生虚拟函数调用的成本,例如:

template< class Derived >
class Base
{
public:
   void foo() 
   {
      static_cast<Derived*>(this)->foo_impl(); // Non virtual derived class call
   }
};

class Derived : public Base<Derived> 
{
private:
   void foo_impl() 
   {
      // Do Stuff
   } 
};

C++11 引入了 final 语言标识符,它将虚拟函数(或类)标记为 Final,告诉编译器不会再对该函数进行重写。

据我了解(来自 Going Native 2013 演示),如果虚拟函数被标记为 final,编译器可以优化代码以消除虚拟函数调用的开销。

因此,在上面的示例中,可以删除 CRTP,并且仍然可以避免虚拟函数调用的开销,只要派生类将虚拟函数标记为 final 即:

class Base
{
public:
   virtual void foo_impl() = 0;

   void foo() 
   {
      foo_impl(); // Non virtual derived class call
   }
};

class Derived : public Base 
{
public:
   // function marked as final, no virtual function call overhead
   virtual void foo_impl() final   
   {
      // Do Stuff
   } 
};

如果是这种情况,是否有关于哪种方法最好的建议?

CRTP 是否仍然是首选,因为它保证函数调用是非虚拟的,而不能依赖基于 final 的优化?

最佳答案

这取决于您如何传递实例。考虑在一个翻译单元中:

Derived d;
foo( &d );

在另一个中:

void foo( Base* b )
{
    b->foo();
}

除了 LTO 之外,编译器没有机会消除虚拟调用开销。

如果是 OTOH,您有:

void foo( Derived* d )
{
    d->foo();
}

编译器现在可以足够智能地优化 vtable 查找,因为它拥有所有必要的信息。但我认为这并不能得到保证。如果没有final,vtable查找仍然是必要的,因为d可能指向从Derived派生的东西,它还有另一个foo_impl()的实现。

关于c++ - CRTP vs 过载和最终,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19363884/

相关文章:

c++ - 使用 tr1 在 C++ 中生成超出范围的随机数

c++ - 与 using 声明冲突的重载

c++ - 如何用 C++ 解码 OggOpus 文件?

c++ - 错误 : invalid parameter type ‘void’

c++ - 迭代器的 std::distance 比 RandomAccessIterator 差

c++ - 由另一个 CRTP 子类访问数据/方法

c++ - CRTP-ed std::vectors 的三向比较

c++ - Curiously Recurring Template Pattern 的实现是特定的吗?

c++ - 特征变换的优先级以及预翻译和翻译之间的差异

c++ - 自定义排序的工作方式出乎意料