4

来自维基百科

// 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必须是抽象的,还是有办法实例化它?

4

5 回答 5

3

我自己的回答是这样的:

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;
于 2011-10-24T16:50:29.437 回答
2

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

于 2011-10-24T10:30:51.637 回答
1

这样做是不合法的,因为内部派生不是一个类,而是一个模板,而不是派生模板的合法参数。

通常这样做的方式是拥有一组派生模板实现,然后每个实现都有一个单独的类,用于将该实现实例化为具体类。

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

};
于 2011-10-24T10:17:55.033 回答
0
derived<derived> obj;

不允许,因为derived它是一个template类并且内部derived尚未完成。它需要有一个像derived<int>.

于 2011-10-24T10:12:35.390 回答
0

没有“只是”派生对象之类的东西,就像你不能拥有 "just" std::vector,也不能拥有float x = sqrt();. 该类型需要一个参数,并且您必须提供它。

于 2011-10-24T10:16:16.460 回答