2016-02-28 84 views
0

由於幾天以來,我被困在模板問題,你一次解決我的每個問題,所以提前謝謝你。CRTP編譯檢測與模板組合

所以我的模板(tl1)誰在乎uml composition,和另一個模板(tl2)至極是uml composed
所以我的目標是,如果composed對象不是tl2如果一個derived不編譯typename D不是tl1 derived

在此之後postone我有下面的代碼的幫助:

#include <type_traits> 
#include <list> 
#include <string> 

template <typename T, typename C> 
class tl2 ; 

template <typename D, typename T> 
class tl1 { 
private: 
    static_assert(std::is_base_of<tl2<T, D>, T>::value, "T should  inherit from tl2"); 
    std::list<T> mTs ; 
    tl1() {} ; 
    friend D ; 
public: 
    T & getTbyName() const ; 
}; 

template <typename T, typename C> 
class tl2 { 
    //static_assert(std::is_base_of<tl1<C, T>, C>::value, "D should inherit from Database"); 
public: 
    std::string getName() { return mName ; } 
private: 
    C & mC ; 
    std::string mName ; 
}; 

class cl1 ; 

class cl2 : public tl2<cl2, int> { 

}; 
class cl1 : public tl1<int, cl2> { 

}; 

我的問題是這樣的編譯非常好,我想不會。 我想不編譯,因爲Dtl1<D, T>必須derivedtl1
而實際上class cl1 : public tl1<int, cl2>是不正確的,但它編譯。所以爲什麼?
如果我改變cl1到它不會編譯:

class cl1 : public tl1<int, cl2> {  
    cl1() {} 
}; 

我明白爲什麼它不會改變後編譯,但我不明白爲什麼它之前編譯。

事實上是tl1tl2將在庫中,所以我想執行庫中的所有檢查。我將無法控制派生,所以我想確保implementationtlX derived

再次感謝您的時間。
Quentin

+0

「我的問題是這樣的編譯非常好,我想不會。」爲什麼?通常問題是某些東西不能編譯,你會希望它能夠complile。 「如果我將cl1更改爲:...它不會編譯......」cl1已經按照您的指示進行了定義,並且這個編譯沒有任何問題。你的問題不清楚,令人困惑。你需要澄清他們。 –

+0

@SamVarshavchik現在的描述更清晰了嗎? –

+1

'std :: is_base_of_,T> :: value'檢查T是否來自t12,,但是你在哪裏檢查'std :: is_base_of:: value'(D從Tl1導出)。 – Brandon

回答

1

做你正在做的事情的問題是週期性的依賴關係。據我所知,std::is_base_of需要完整的類型才能工作。

您的代碼已經在TL1兩個限制..

  • T必須從TL2繼承
  • d必須從TL1

最終繼承,它結束了看起來像:

tl1<T, D>其中D繼承tl1<T, D>其中D繼承tl1<T, D>

換句話說,D永遠不會被定義,因爲Tl1需要D的定義作爲模板參數,但是D必須從需要它的Tl1繼承。

現在,如果您刪除D上的限制,那麼下面的代碼將按原樣進行編譯,因爲符合第一個限制。但是,如果取消註釋tl1中的static_assert,它將永遠不會編譯,因爲D的定義取決於tl1的定義,這取決於D的定義,依此類推......等等。

你會得到這樣的錯誤:

invalid use of incomplete type 'class cl1' 
    struct is_base_of 
      ^
note: forward declaration of 'class cl1' 

代碼:

#include <type_traits> 
#include <list> 
#include <string> 

template <typename T, typename C> 
class tl2 ; 

template <typename D, typename T> 
class tl1 { 
private: 
    static_assert(std::is_base_of<tl2<T, D>, T>::value, "T should  inherit from tl2"); 
    //static_assert(std::is_base_of<tl1, D>::value, "D should inherit from tl1"); 
    std::list<T> mTs ; 
    friend D ; 
public: 
    tl1() {} 
    T & getTbyName() const ; 
}; 

template <typename T, typename C> 
class tl2 { 
    //static_assert(std::is_base_of<tl1<C, T>, C>::value, "D should inherit from Database"); 
public: 
    std::string getName() { return mName ; } 
private: 
    //C & mC ; 
    std::string mName ; 
}; 


class cl1; 

class cl2 : public tl2<cl2, cl1> { 
    public: 
     cl2() {} 
}; 

class cl1 : public tl1<cl1, cl2> { 
    public: 
     cl1() {} 
}; 

int main() { 
    cl1 a; 
    cl2 b; 
    return 0; 
} 

如果您要更換std::is_base_of有:

template<class B, class D> 
struct is_base_of 
{ 
    template<typename T> struct dummy {}; 
    struct Child : D, dummy<int> {}; 

    static B* Check (B*); 
    template<class T> static char Check (dummy<T>*); 

    static const bool value = (sizeof(Check((Child*)0)) == sizeof(B*)); 
}; 

它會給你的錯誤:

recursively required by substitution of 'template<class T> static char is_base_of<B, D>::Check(is_base_of<B, D>::dummy<T>*) [with T = <missing>]'

在我看來,對於發生的事情來說,哪個更清晰。

TLDR:你不行。

+0

謝謝你的建設性答案(和你的時間)。這就是爲什麼'tl1'構造函數是私有的。但我不明白爲什麼'class cl1:public tl1 '不會尖叫...... –

+0

@ QuentinHuot-Marchand,通常不允許在標準庫模板中使用不完整的類型,並且您可能會簡單地獲取未定義的行爲if你做。有一些例外,但是,當你使用任何帶有不完整類型的模板時,你不能指望編譯器尖叫 - 沒有辦法對模板進行編程,以便在與不完整類型一起使用時產生錯誤,或者根本檢測到這一點。 –

+0

@ChrisBeck我明白了,我想我必須解決這個問題。謝謝你的時間 –

1

您的代碼編譯,因爲靜態斷言沒有錯。

CL1專業TL1與

T = cl2tl2<cl2, int> D = int

繼承然後你驗證

std::is_base_of<tl2<T, D>, T>::value == true 

讓我們更換TD這裏:

std::is_base_of<tl2<cl2, int>, cl2>::value == true 

而且這是正確的。

換句話說,你的靜態斷言可能不檢查它應該做什麼。截至目前,我有點困惑你想達到什麼目的。我會針對你之前的問題發表一個答案,但你應該認真考慮讓你的名字更清楚。這將有助於理解您打算實現的目標。

從@Brandon反饋之後,我猜你可能會尋找這樣的:http://ideone.com/H4hm3O