2010-04-01 32 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)); 
    } 
};