2014-03-24 36 views
7
template <typename T> 
class Base 
{ 
private: 
    typename T::B c; 
}; 

class A : public Base<A> 
{ 
public: 
    class B; 
}; 

這樣的事情甚至可能嗎? VC++ 2013說B是不是A的成員從模板類Base <A>衍生出A類,以便Base <A>可以使用A :: B?

+4

你不能,而GCC的錯誤更具描述性,至於爲什麼http://ideone.com/90siYB – StoryTeller

+1

你可以修改哪些類來引入解決方法? – pmr

+0

在你的實際代碼中,B是一個類型還是一個成員變量? –

回答

1

我會是這樣的(live example):

template<typename T> struct Impl; 
template<typename T> struct Nested; 

template <typename T> 
class Base 
{ 
private: 
    typename Nested<T>::type c; 
}; 

struct A; 

template<> struct Impl<A> { class B { }; }; 
template<> struct Nested<A> { using type = typename Impl<A>::B; }; 

struct A : Base<A>, Impl<A> 
{ 
    //... 
}; 

這裏,類Impl包含A一部分不依賴於Base,也就是嵌套類B。因此A現在衍生出Base<A>Impl<A>

Nested只包含指定上述嵌套類的別名的別名。現在BaseNested讀取此類型並定義其數據成員,此類型。

在我們專門爲它設計ImplNested之前,我們需要聲明A。並且在定義A之前我們需要這些專業化,因爲此時Base<A>已實例化,並且這需要Nested<A>已完成,這又要求Impl<A>已完成。

Philip's answer的主要區別是,職責分離多:

  • Base沒有得到任何東西,所以有較少的被污染的機會。我們只將其數據成員的類型更改爲typename Nested<T>::type,就是這樣。

  • Nested是一種純粹的性狀特徵。它只定義別名type,就是這樣。

  • Impl是一個實現類。它包含嵌套類B的定義或可能不依賴於Base的任何其他內容。


順便說一句,Stroustrup的的The C++ Programming Language第4版有771頁的下面的代碼:

template<typename N> 
struct Node_base : N::balance_type { }; 

template<typename Val, typename Balance> 
struct Search_node : Node_base<Search_node<Val, Balance> > 
{ 
    using balance_type = Balance; 
}; 

具有完全相同的問題。

+0

謝謝。我會消化這一點,高級模板編程對我來說是一個遙遠的話題。 – NFRCR

6

故事

如直接在你的問題的意見你正在嘗試簡單地完成規定是不可能的,因爲它是非法的指代不完整類型(其中T = ABase內)。


變通方法

在CRTP的情況下的通用解決方法是使用一個trait表示成員,應該在兩者DerivedBase可用的,但它們並非意在聲明/定義在Base

儘管這並不等同於你正在努力完成的任務,但它非常接近它,並且遵循了某種等同的語義。

template<class> struct some_trait;  // primary template 

template <class T> 
struct A : some_trait<T> {    // (1) 
    typename some_trait<T>::C a; 
}; 

template<> struct some_trait<struct B> { // (2) 
    class C { }; 
}; 

struct B : A<B> {      // (3) 
    C b; 
}; 

int 
main (int argc, char *argv[]) 
{ 
    B a; // legal 
} 

爲什麼解決方法......工作?

把它縮短;我們不再嘗試訪問不完整類型的內部結構。

some_trait<B>是一個完整的類型其直接的定義(即專業化)標記(2)後,正因爲如此它可以通過(1)(3),而不會造成任何問題,可以使用。

+0

這[不會編譯](http://coliru.stacked-crooked.com/a/e9cc460456d07316)。你需要'使用C = typename some_trait :: C;'在'A'中。 – iavr

+0

另外,struct'B'現在有兩個* C類型的數據成員。 – iavr

+0

@iavr我其實並沒有嘗試在發佈之前編譯這個代碼片段,我犯了一個愚蠢的錯誤,我會將其改爲100%合法。 –

相關問題