2013-04-10 37 views
8

Derlemenin bir bölümünü içeren büyük bir proje üzerinde çalışıyorum - ama nasıl olduğunu anlamıyorum. dolayısıyla dairesel olduğunu ... kendisi First<Traits> dayalı bir typedef olan Two dayalı bir typedef olanBu şablon kodu neden derleniyor?

template <typename T> 
struct First { 
    typedef int type;   // (A) 
    typename T::Three order; // (B) 
}; 

template <typename T> struct Second { 
    typedef typename T::type type; 
}; 


template <typename T> struct Third { 
    int val; 
    T two; 
}; 

struct Traits { 
    typedef First<Traits> One; 
    typedef Second<One> Two; 
    typedef Third<Two> Three; 
}; 

int main(int argc, char** argv) { 
    Traits::One x; 
}; 

sınıf FirstTraits ve referanslar Traits::Three, üzerinde şablon edilir: Bu basit örnekte için aşağı damıtılmış . Ancak bu kod hem gcc4.6 hem de VC10'da iyi derler. Ancak, (A) ve (B) işaretli iki satırın sırasını değiştirirseniz, kod 'un Second'un içinden şikayetçi olmaz.

Bu kod neden derleniyor ve bu nedenle neden typedef ve üye değişkeninin sıralaması önemlidir?

+0

deneyin ağaçta kağıda bu şekilde çizmek için: Her tanımı için bir düğüm yapın ve ardından her biri için (ileri) türleri bildirim ve için tam bir tanım ihtiyacı vardır ve bir ihtiyacı olan hangi kenarlarını çizin sadece beyan, ve bunun dairesel olmayacağını göreceksiniz. – PlasmaHH

+0

Merhaba - ilgisiz, ama P0704 17 karşı karşı bir DR olup olmadığını biliyor musunuz? –

+0

@Kerrek Hiçbir fikrim, böyle şeylerin nasıl karar verildiğini bile bilmiyorum. – Barry

cevap

3

Söylemeye değer birkaç şey var.

  • Second zinciri "dan ... örneği" ve bir "eksik türü" hatası ile biten uzun olan

    T badObject; 
    

    içerecek biçimde değiştirilirse kod nedeniyle dairesellikten size kıracak beklemek, ancak bunun yerine derleyici akıllıca bunu gözlemleyerek olduğunu tamamensaklanması gerekmez Bu sizi anlatıyor

    typename T::type object; 
    

    eklerseniz, sadece ne T::type olduğunu bilmek için. Bunu açıklamak için, T hayır anda hissetme tanımlı nesneleri içerdiğinden yasal olarak

    First { ... typedef T type; ... } 
    Second { typename T::type object; } 
    

    olabilir notu ya

    First { ... typedef typename T::One type; ... } 
    Second { typedef typename T::type object; } 
    

    Second yılında typedef beri herhangi bir nesne örneğini gerektirmez ya - ama değil, diyelim ki,

    First { ... typedef typename T::One type; ... } 
    Second { typename T::type object; } 
    

    sadece o zamandan beri derleyici aslında bir First<Traits> nesnesini First<Traits> nesnesinin içine yerleştirmek için gereklidir. (A) takas ve (B) ile

  • konu

  • derleyici yukarıdaki çekti zeki hüner seferinde anda sadece bir satır ayrıştırma, her ihtisas şablonun tanımının yeni bir kopyasını tanıtarak çalışıyor olmasıdır.Hata, 'da, tür tanımlaması Second tarafından bilinmesi gerektiğinde, bu tür tanımlamaya sahip olmadığında oluşur.

+1

Harika teşekkürler, bu mükemmel. Derleyicinin her seferinde bir satıra gidebileceğini fark etmedim. – Barry

+0

Belirtimi kontrol etmedim, ancak bunun olası tek sorun olduğunu varsayalım. Bunu düşünürseniz, zaten şeylerin çizgiye dönüştüğünü zaten biliyordunuz - bu yüzden A sınıfı {}; B sınıfı: A; ve B sınıfı: A; A sınıfı {}; 'farklıdır! – Sharkos

1

typedef için tam bir tür gerekmez.

+0

Ancak bu derleme yapmıyor: 'template struct Foo { typedef typename Türetilmiş :: tür tipi; }; struct Bar: public Foo { typedef int türü; }; int main (int argc, char ** argv) { Bar b; } ' – Barry

+0

@Barry: Fark, 'Bar'ın Foo ' (miras nedeniyle) ve Foo'nun 'typedef' tanımının' Bar' için değil, yuvalanmış bir türe göre tanımlanması gerektiğidir. Yuvalanmış bir tür * üye * ve ek tür tamamlanmış olmalıdır. –

1

Sağladığımdan daha iyi bir yanıtı kabul ettiniz - bu yüzden benimkini kaldırıyorum. Ancak, örneğinize daha fazla bir indirim yapmak isteyebileceğinizi düşündüm. Orijinal kodunuza geri dönmek için iki satır A ve B olarak işaretledim. Eğer onları çevirirseniz, örneğinizde olduğu gibi, derleme başarısız olur.

template<typename T> 
struct First 
{ 
     typedef typename T::type type; 
}; 

struct Second 
{ 
     typedef int type; // (A) 
     First<Second> order; // (B) 
}; 


int main(int argc, char** argv) 
{ 
     Second x; 
}; 
İlgili konular