问题
From Wikipedia:
// The Curiously Recurring Template Pattern (CRTP)
template <typename T>
struct base
{
// ...
};
struct derived : base<derived>
{
// ...
};
Now if I want derived_from_derived
, I can write:
// The Curiously Recurring Template Pattern (CRTP)
template <typename T>
struct base
{
// ...
};
template <typename T>
struct derived : base<T>
{
// ...
};
struct derived_from_derived : derived <derived_from_derived>
{
// ...
};
Now suppose I just want a derived
object. This doesn't work:
derived<derived> obj;
Does derived
have to be abstract, or is there a way to instantiate it?
回答1:
Support for deeper inheritance hierarchies with CRTP usually is implemented by "inserting" CRTP classes between your own classes in the inheritance hierarchy:
struct empty
{};
template <class Derived, class Base = empty>
struct crtp_services : Base
{};
class base : public crtp_services<base>
{};
class derived : public crtp_services<derived, base>
{};
class derived_of_derived : public crtp_services<derived_of_derived, derived>
{};
回答2:
My own answer is this:
struct base
{
template <typename T>
struct type
{
// ...
};
};
struct derived
{
template <typename T=derived>
struct type : base::type<T>
{
// ...
};
}
struct derived_from_derived
{
template <typename T=derived_from_derived >
struct type : derived::type<T>
{
// ...
};
};
Now I can have a derived::type<> obj
. Also, parametized inheritance works (e.g. decorator pattern):
template <typename whatever>
struct derived_from_whatever
{
template <typename T=derived_from_whatever>
struct type : whatever::type<T>
{
// ...
};
};
derived_from_whatever<derived_from_derived>::type<> obj_whatever;
回答3:
It's not legal to do that, since the inner derived is not a class, but is itself a template, and not a legal argument for the derived template.
The way that this is usually done is to have a set of derived templates implementations, and then each implementation has a separate class which is used to instantiate that implementation as a concrete class.
template <typename T>
struct base
{
};
template <typename T>
struct derived_impl : base<T>
{
};
struct derived : derived_impl<derived>
{
};
template <typename T>
struct derived_of_derived_impl: derived_impl<T>
{
};
struct derived_of_derived : derived_of_derived_impl<derived_of_derived>
{
};
回答4:
derived<derived> obj;
is not allowed because derived
is a template
class and the inner derived
is not yet complete. It needs to have a type like derived<int>
.
回答5:
There's no such thing as "just" a derived object, just like you cannot have "just" std::vector
, nor can you have float x = sqrt();
. The type requires an argument, and you must provide it.
来源:https://stackoverflow.com/questions/7873989/c-crtp-class-hierarchy