C
chsalvia
The "Curiously Recurring Template Pattern" (CRTP) recently caught my
attention as a nice trick which allows static polymorphism. In other
words, it lets you build extensible classes without the overhead of
virtual function calls. (But of course, with the limitation of
compile-time resolving.)
Basically, you create a templated Base Class which defines an
interface function that uses a static_cast to call a member function
in Derived. Then the Derived class inherits from the templated Base
class with Derived as a template argument.
template <class Derived>
struct Base
{
void work()
{
static_cast<Derived*> (this)->work();
}
};
struct Derived : public Base<Derived>
{
void work()
{
cout << "Derived class function." << endl;
}
};
template <class T>
void func(Base<T>& Object)
{
Object.work();
}
int main()
{
Derived D;
func(D);
}
This is a nice way to make extensible classes without using runtime
polymorphism. But the more I think about it, it seems kind of
pointless. If you want to build extensible classes with static
polymorphism, you can just use templates to simply do something like
this:
template <class T>
void func(T& Object)
{
Object.work();
}
This way any class that defines a work() member function can be passed
to func(), and the correct member function will be called. This is a
lot simpler than CRTP. So what's the real advantage of CRTP then?
The only advantage I see is that CRTP works with the inheritance
hierarchy, just like normal polymorphism, rather than letting you use
any class which defines a certain member function name.
Am I correct here, or am I overlooking the value of CRTP somehow?
attention as a nice trick which allows static polymorphism. In other
words, it lets you build extensible classes without the overhead of
virtual function calls. (But of course, with the limitation of
compile-time resolving.)
Basically, you create a templated Base Class which defines an
interface function that uses a static_cast to call a member function
in Derived. Then the Derived class inherits from the templated Base
class with Derived as a template argument.
template <class Derived>
struct Base
{
void work()
{
static_cast<Derived*> (this)->work();
}
};
struct Derived : public Base<Derived>
{
void work()
{
cout << "Derived class function." << endl;
}
};
template <class T>
void func(Base<T>& Object)
{
Object.work();
}
int main()
{
Derived D;
func(D);
}
This is a nice way to make extensible classes without using runtime
polymorphism. But the more I think about it, it seems kind of
pointless. If you want to build extensible classes with static
polymorphism, you can just use templates to simply do something like
this:
template <class T>
void func(T& Object)
{
Object.work();
}
This way any class that defines a work() member function can be passed
to func(), and the correct member function will be called. This is a
lot simpler than CRTP. So what's the real advantage of CRTP then?
The only advantage I see is that CRTP works with the inheritance
hierarchy, just like normal polymorphism, rather than letting you use
any class which defines a certain member function name.
Am I correct here, or am I overlooking the value of CRTP somehow?