2009-03-06 23 views
1

Aşağıdaki basit programın üç yinelemesini denedim. Bu, kapsayıcı ve yineleyici bir sınıf çifti yazmak için oldukça basitleştirilmiş bir girişimdir, ancak tamamlanmamış türlerle (ileri bildirimler) sorunlara koşuyordum. Herşeyi tempize ettikten sonra bunun aslında mümkün olduğunu keşfettim - ama sadece şablon parametresini kullansaydım! (Bunu, Google sparsetable code'a bakarak farkettim.)C++ şablonları neden eksik türleri (ileri bildirimler) atlamama izin veriyor?

İkinci neden üçüncü sırada çalışmayanı açıklayan tüm ipuçları? (Neden birinin işe yaramadığını biliyorum - derleyicinin kapsayıcının bellek düzenini bilmesi gerekir.)

Şimdiden teşekkürler.

// This doesn't work: invalid use of incomplete type. 
#if 0 
struct container; 
struct iter { 
    container &c; 
    int *p; 
    iter(container &c) : c(c), p(&c.value()) {} 
}; 
struct container { 
    int x; 
    int &value() { return x; } 
    iter begin() { return iter(*this); } 
}; 
int main() { 
    container c; 
    c.begin(); 
    return 0; 
} 
#endif 

// This *does* work. 
template<typename T> struct container; 
template<typename T> struct iter { 
    container<T> &c; 
    T *p; 
    iter(container<T> &c) : c(c), p(&c.value()) {} 
}; 
template<typename T> struct container { 
    T x; 
    T &value() { return x; } 
    iter<T> begin() { return iter<T>(*this); } 
}; 
int main() { 
    container<int> c; 
    c.begin(); 
    return 0; 
}; 

// This doesn't work either. 
#if 0 
template<typename T> struct container; 
template<typename T> struct iter { 
    container<int> &c; 
    int *p; 
    iter(container<int> &c) : c(c), p(&c.value()) {} 
}; 
template<typename T> struct container { 
    int x; 
    int &value() { return x; } 
    iter<int> begin() { return iter<int>(*this); } 
}; 
int main() { 
    container<int> c; 
    c.begin(); 
    return 0; 
} 
#endif 
+0

Aslında "ne işe yaramazsa" ne daha spesifik olabilir misiniz? Derleme başarısız mı, eğer öyleyse mesaj nedir? Doğru koşmayı başaramaz mı, eğer öyleyse bunu beklemediğini ne yapar? –

+0

, belirttiğim iletiyle derlemeyi başaramadı: "tamamlanmamış türde geçersiz kullanım." – Yang

cevap

4

Bir kopya işlemi yaptığınızdan, ilk önce container tanımını gerektirir. iter yapıcısını container tanımından sonra tanımlarsanız iyi olur. Yani: gerçekte main işlevinde bir örneğini kadar hiçbir sınıf olmadığından

struct container; 
struct iter { 
    container &c; 
    int *p; 
    iter(container &c); 
}; 

struct container { 
    int x; 
    int &value() { return x; } 
    iter begin() { return iter(*this); } 
}; 

iter::iter(container &c) : c(c), p(&c.value()) {} 

int main() { 
    container c; 
    c.begin(); 
    return 0; 
} 

ikinci örnek çalışır. O zaman bütün tipler tanımlanır. Ana öğeden sonra iter veya container şablon tanımlarını taşımayı deneyin ve bir hatayla karşılaşırsınız.

Üçüncü örnek, int için bir uzmanlıktır ya da görünür. Bu, iter için şablon parametresi kullanılmadığı için derlenmelidir. Uzmanlık söz dizimini biraz kapalı tuttun. Ancak, uygun bir kurucu yoktur, böylece sadece x için çöp alırsınız. Ayrıca, yineleyiciler işaretçiler tarafından iyi modellenmiştir. this'un değerini geçmek çok fazla yardımcı olmayacaktır. Yineleyiciler tipik olarak tek bir nesne değil, bir dizi için gereklidir. Yine de, bir tane inşa etmenizi engelleyebilecek hiçbir şey yok.

Bir işlev gövdesinden sonra ;'a ihtiyacınız yoktur.

+0

İki sentim - "bu değerin geçilmesi" den bahsettiniz ve biraz daha fazla ayrıntı yardımcı olabilir. * Bu döndürürseniz/iletirseniz, bir referansınız olur, +/- çıkarılmış niteleyiciler. Eğer 'this' döndürürseniz, şu anki nesneye ham bir işaretçiniz olur ve nesnenin ömrü boyunca endişelenmeniz gerekir.Çoğunlukla dinamik bellek mgmt için geçerli olan bağlamlar arasında geçmek için bir işaretçiye ihtiyacınız varsa, en iyi uygulama bir akıllı (benzersiz/paylaşılan) işaretçi veya karşılaştırılabilir bir RAII türüdür. (Hala bunu yapabilirsin, ama ideal olarak sadece işlevleri engellemek için.) Eklemek/düzeltmek için bir şey var mı? –

2

Sen ITER tanımlayarak şablonlar olmadan bu yapabileceğini :: iter() kabın tanımından sonra: şablonları örneğini her iki sınıfları tamamen tanımlanmıştır çünkü

struct container; 

struct iter { 
    container &c; 
    int *p; 
    iter(container &c); 
}; 

struct container { 
    int x; 
    int &value() { return x; } 
    iter begin() { return iter(*this); } 
}; 

iter::iter(container &c) 
    : c(c), p(&c.value()) {} 

int main() { 
    container c; 
    c.begin(); 
    return 0; 
} 

Şablon versiyonu çalışır.

0

İlk durumda, sınıf tanımlanmadan önce Container sınıfının bir üye işlevine erişmeye çalışıyorsunuz, bu nedenle çalışmaz. İkinci durumda, belirli bir türle ilk kez kullanıldığında şablon başlatılır. Bu noktada, Konteyner sınıfı ana olarak tanımlanmış ve böylece derlenmiştir. Üçüncü durumda, dairesel bir referans bulunmaktadır. kapsayıcı kullanır iter ve iter konteyner kullanır, bu yüzden çalışamaz.

İlgili konular