2010-04-01 42 views
9

我试图编写一个基于策略的宿主类(即从其模板类继承的类),并带有扭曲,其中策略类也由主机类,以便它可以访问它的类型。一个可能有用的例子是一个策略(像mixin那样使用),用一个多态的clone()方法来扩充宿主类。下面是我想要做的一个小例子:在C++中使用基于策略的设计与CRTP混合使用

template <template <class> class P> 
struct Host : public P<Host<P> > { 
    typedef P<Host<P> > Base; 
    typedef Host* HostPtr; 
    Host(const Base& p) : Base(p) {} 
}; 

template <class H> 
struct Policy { 
    typedef typename H::HostPtr Hptr; 
    Hptr clone() const { 
    return Hptr(new H((Hptr)this)); 
    } 
}; 

Policy<Host<Policy> > p; 
Host<Policy> h(p); 

int main() { 
    return 0; 
} 

很不幸,无法编译,在什么我看来,像圆形的类型依赖:

try.cpp: In instantiation of ‘Host<Policy>’: 
try.cpp:10: instantiated from ‘Policy<Host<Policy> >’ 
try.cpp:16: instantiated from here 
try.cpp:2: error: invalid use of incomplete type ‘struct Policy<Host<Policy> >’ 
try.cpp:9: error: declaration of ‘struct Policy<Host<Policy> >’ 
try.cpp: In constructor ‘Host<P>::Host(const P<Host<P> >&) [with P = Policy]’: 
try.cpp:17: instantiated from here 
try.cpp:5: error: type ‘Policy<Host<Policy> >’ is not a direct base of ‘Host<Policy>’ 

如果任何人能发现的明显的错误,或成功地在政策中混用CRTP,我将不胜感激任何帮助。

回答

6

事实上,问题是由于HostPtr声明在您从策略继承时尚未见到。关于这些声明在实例化模板中可见的确切语义有一些讨论,其中有非常复杂的问题,请参阅this defect report

但是在你的情况中,情况很明显:在类体之前,没有代码可以看到类成员的任何声明,所以你的代码失败了。你可以通过类型作为模板参数

template <template <class,class> class P> 
struct Host : public P<Host<P>, Host<P>* > { 
    typedef P<Host<P> > Base; 
    Host(const Base& p) : Base(p) {} 
}; 

template <class H, class Hptr> 
struct Policy { 
    typedef Hptr HostPtr; 
    HostPtr clone() const { 
    return Hptr(new H((Hptr)this)); 
    } 
}; 

如果有更多的类型,你可以决定通过一个特质

template <class Host> 
struct HTraits { 
    typedef Host *HostPtr; 
    // ... 
}; 

template <template <class,class> class P> 
struct Host : public P<Host<P>, HTraits< Host<P> > > { 
    typedef P<Host<P> > Base; 
    Host(const Base& p) : Base(p) {} 
}; 

template <class H, class Htraits> 
struct Policy { 
    typedef typename Htraits::HostPtr HostPtr; 
    HostPtr clone() const { 
    return Hptr(new H((Hptr)this)); 
    } 
};