问题
How can I use CRTP in C++ to avoid the overhead of virtual member functions?
回答1:
There are two ways.
The first one is by specifying the interface statically for the structure of types:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo(); // required to compile.
};
struct your_type : base<your_type> {
void foo(); // required to compile.
};
The second one is by avoiding the use of the reference-to-base or pointer-to-base idiom and do the wiring at compile-time. Using the above definition, you can have template functions that look like these:
template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
obj.foo(); // will do static dispatch
}
struct not_derived_from_base { }; // notice, not derived from base
// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload
So combining the structure/interface definition and the compile-time type deduction in your functions allows you to do static dispatch instead of dynamic dispatch. This is the essence of static polymorphism.
回答2:
I've been looking for decent discussions of CRTP myself. Todd Veldhuizen's Techniques for Scientific C++ is a great resource for this (1.3) and many other advanced techniques like expression templates.
Also, I found that you could read most of Coplien's original C++ Gems article at Google books. Maybe that's still the case.
回答3:
I had to look up CRTP. Having done that, however, I found some stuff about Static Polymorphism. I suspect that this is the answer to your question.
It turns out that ATL uses this pattern quite extensively.
回答4:
This Wikipedia answer has all you need. Namely:
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
Although I don't know how much this actually buys you. The overhead of a virtual function call is (compiler dependent, of course):
- Memory: One function pointer per virtual function
- Runtime: One function pointer call
While the overhead of CRTP static polymorphism is:
- Memory: Duplication of Base per template instantiation
- Runtime: One function pointer call + whatever static_cast is doing
来源:https://stackoverflow.com/questions/262254/crtp-to-avoid-dynamic-polymorphism