質問

I often use CRTP to call a derived class function from a base class. It has the bonus of not incurring the cost of a virtual function call, e.g:

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 introduced the final language identifier which marks a virtual function (or class) as final, telling the compiler that there will be no further overrides of the function.

It is my understanding (from the Going Native 2013 presentations) that if a virtual function is marked as final the compiler can optimize the code to eliminate the overhead of the virtual function call.

Ergo In the example above the CRTP can be removed and the overhead of the virtual function call is still avoided, providing the derived class marks the virtual function as final i.e.:

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
   } 
};

If this is the case are there any recommendations as to which is the best approach?

Should CRTP still be preferred since it guarantees that function call is non virtual, where as optimizations based on final cannot be relied upon?

役に立ちましたか?

解決

It depends on how you pass the instance around. Consider in one translation unit:

Derived d;
foo( &d );

and in another:

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

except for LTO, there is no chance for the compiler to remove the virtual call overhead.

If OTOH, you have:

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

The compiler could now be smart enough to optimize the vtable lookup away as it has all the necessary information. I don't think it is guaranteed, though. Without final, the vtable lookup would still be necessary as d could point to something derived from Derived which has yet another implementation of foo_impl().

他のヒント

My 5cents on this:

Recent GCC optimize virtual functions when class name is known.

Also the standard say if class name is known, the virtual function may be inlined - e.g. no virtual dispatch.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top