C ++ CRTP иерархия классов - PullRequest
       15

C ++ CRTP иерархия классов

4 голосов
/ 24 октября 2011

Из Википедия :

// The Curiously Recurring Template Pattern (CRTP)
template <typename T>
struct base
{
    // ...
};
struct derived : base<derived>
{
    // ...
};

Теперь, если я хочу derived_from_derived, я могу написать:

// 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>
{
    // ...
};

Теперь предположим, что я просто хочу derived объект.Это не работает:

derived<derived> obj;

Должен ли derived быть абстрактным или есть способ его создания?

Ответы [ 5 ]

2 голосов
/ 24 октября 2011

Мой собственный ответ таков:

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>
    {
        // ...
    };
};

Теперь я могу получить derived::type<> obj.Также работает параметризованное наследование (например, шаблон декоратора):

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;
2 голосов
/ 24 октября 2011

Поддержка более глубоких иерархий наследования с помощью CRTP обычно реализуется путем «вставки» классов CRTP между вашими собственными классами в иерархию наследования:


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

1 голос
/ 24 октября 2011

Это недопустимо, поскольку внутреннее производное не является классом, но само является шаблоном, а не допустимым аргументом для производного шаблона.

Способ, которым это обычно делается, состоит в том, чтобы иметь набор реализаций производных шаблонов, а затем каждая реализация имеет отдельный класс, который используется для создания экземпляра этой реализации в виде конкретного класса.

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>
{

};
0 голосов
/ 24 октября 2011

Нет такой вещи, как "просто" производный объект, точно так же, как вы не можете иметь "просто" std::vector, и при этом вы не можете иметь float x = sqrt();.Тип требует аргумент, и вы должны предоставить его.

0 голосов
/ 24 октября 2011
derived<derived> obj;

не допускается, поскольку derived является классом template, а внутренний derived еще не завершен.Это должно иметь тип как derived<int>.

...