Çoğu jenerik uygulama (ya da daha doğrusu: parametrik polimorfizm) tip silme kullanmaktadır. Bu, genel kod derleme sorununu büyük ölçüde basitleştirir, ancak yalnızca kutulu tipler için çalışır: her bir argüman etkili bir şekilde opak bir işaretçi olduğundan, argümanlar üzerinde işlem yapmak için VTable veya benzer bir gönderme mekanizmasına ihtiyacımız vardır. Java dilinde:
<T extends Addable> T add(T a, T b) { … }
derlenebilir, tür denetlenebilir ve aynı şekilde çağrılabilir
Addable add(Addable a, Addable b) { … }
bunun dışında jenerikler tip denetleyicisine çağrı sitesinde çok daha fazla bilgi sağlar. Bu ekstra bilgiler , özellikle genel tipler çıkarıldığında tip değişkenleriyle ele alınabilir . Tür denetimi sırasında, her genel tür bir değişkenle değiştirilebilir, diyelim $T1
:
$T1 add($T1 a, $T1 b)
Daha sonra tür değişkeni, somut bir tür ile değiştirilinceye kadar, daha fazla gerçekle güncellenir. Tür kontrol algoritması, henüz tam bir türe çözümlenmemiş olsalar bile bu tür değişkenleri barındıracak şekilde yazılmalıdır. Java'nın kendisinde bu genellikle kolayca yapılabilir çünkü işlev çağrısı türünün bilinmesi gerekmeden önce argümanların türü genellikle bilinir. Dikkate değer bir istisna, bu tür değişkenlerin kullanılmasını gerektiren fonksiyon argümanı olarak lambda ifadesidir.
Çok daha sonra, bir iyileştirici olabilir argümanlar belirli bir dizi için özel kod oluşturmak, bu daha sonra etkili bir satır içine alma bir tür olacaktır.
Genel işlev tür üzerinde herhangi bir işlem gerçekleştirmezse, yalnızca bunları başka bir işleve geçirirse, genel tür argümanları için bir VTable'dan kaçınılabilir. Örneğin Haskell fonksiyonunun argümanı kutlaması call :: (a -> b) -> a -> b; call f x = f x
gerekmeyecekti x
. Ancak, bu, boyutlarını bilmeden değerlerden geçebilen ve aslında onu yine de işaretçilerle sınırlayan bir çağrı kuralı gerektirir.
C ++ bu açıdan çoğu dilden çok farklıdır. Şablonlu bir sınıf veya işlev (burada yalnızca şablonlanmış işlevleri tartışacağım) kendi içinde çağrılamaz. Bunun yerine, şablonlar, gerçek bir işlev döndüren bir derleme zamanı meta işlevi olarak anlaşılmalıdır. Şablon argüman çıkarımını bir an için yok sayarak, genel yaklaşım daha sonra şu adımlara dayanır:
Şablonu sağlanan şablon bağımsız değişkenlerine uygulayın. Örneğin çağırarak template<class T> T add(T a, T b) { … }
olarak add<int>(1, 2)
bize gerçek işlevini verecekti int __add__T_int(int a, int b)
(isim-bozma yaklaşım kullanılır ya da her neyse).
Geçerli derleme biriminde bu işlevin kodu zaten oluşturulmuşsa, devam edin. Aksi takdirde, kodu int __add__T_int(int a, int b) { … }
kaynak koduna bir işlev yazılmış gibi oluşturun . Bu, şablon bağımsız değişkeninin tüm tekrarlarının değerleriyle değiştirilmesini içerir. Bu muhtemelen bir AST → AST dönüşümüdür. Ardından, oluşturulan AST üzerinde tip kontrolü yapın.
Çağrıyı kaynak kodu kullanılmış gibi derleyin __add__T_int(1, 2)
.
C ++ şablonlarının, burada tanımlamak istemediğim aşırı yük çözünürlüğü mekanizması ile karmaşık bir etkileşimi olduğunu unutmayın. Ayrıca, bu kod oluşturma işleminin sanal olan şablonlanmış bir yönteme sahip olmayı imkansız kıldığına dikkat edin - tür silme tabanlı bir yaklaşım bu önemli kısıtlamadan muzdarip değildir.
Bu derleyiciniz ve / veya diliniz için ne anlama geliyor? Sunmak istediğiniz tür jenerikleri dikkatlice düşünmelisiniz. Tür çıkarımının olmadığı durumlarda tür silme, kutulu türleri destekliyorsanız mümkün olan en basit yaklaşımdır. Şablon uzmanlığı oldukça basit görünmektedir, ancak şablonlar tanım sitesinde değil çağrı sitesinde somutlaştırıldığından, genellikle ad yönetimi ve (çoklu derleme birimleri için) çıktıda önemli bir tekrarlama içerir.
Gösterdiğiniz yaklaşım aslında C ++ benzeri bir şablon yaklaşımıdır. Ancak, özel / somutlaştırılmış şablonları ana şablonun "sürümleri" olarak depolarsınız. Bu yanıltıcıdır: kavramsal olarak aynı değildirler ve bir işlevin farklı örneklemelerinin çılgınca farklı türleri olabilir. İşlev aşırı yüklenmesine de izin verirseniz, uzun vadede işleri zorlaştıracaktır. Bunun yerine, bir adı paylaşan tüm olası işlevleri ve şablonları içeren bir aşırı yük kümesi kavramına ihtiyacınız olacaktır. Aşırı yüklemeyi çözmek dışında, farklı örneklenmiş şablonların birbirinden tamamen ayrı olduğunu düşünebilirsiniz.