Itu karena persyaratan untuk kompilasi yang terpisah dan karena templat adalah polimorfisme gaya instantiation.
Mari kita sedikit lebih dekat ke konkret untuk penjelasan. Katakanlah saya punya file berikut:
- foo.h
- mendeklarasikan antarmuka
class MyClass<T>
- foo.cpp
- mendefinisikan implementasi
class MyClass<T>
- bar.cpp
Kompilasi terpisah berarti saya harus dapat mengkompilasi foo.cpp secara independen dari bar.cpp . Kompiler melakukan semua kerja keras analisis, optimisasi, dan pembuatan kode pada setiap unit kompilasi sepenuhnya secara independen; kita tidak perlu melakukan analisis seluruh program. Hanya tautan yang perlu menangani keseluruhan program sekaligus, dan pekerjaan tautan jauh lebih mudah.
bar.cpp bahkan tidak perlu ada ketika saya mengkompilasi foo.cpp , tapi saya masih bisa menghubungkan foo.o yang sudah saya miliki bersama bar.o saya baru saja diproduksi, tanpa perlu mengkompilasi ulang foo. .cpp . foo.cpp bahkan dapat dikompilasi ke perpustakaan dinamis, didistribusikan di tempat lain tanpa foo.cpp , dan ditautkan dengan kode yang mereka tulis bertahun-tahun setelah saya menulis foo.cpp .
"Instantiation-style polymorphism" berarti bahwa templat MyClass<T>
tersebut tidak benar-benar kelas generik yang dapat dikompilasi dengan kode yang dapat bekerja dengan nilai berapa pun T
. Yang akan menambah biaya overhead seperti tinju, perlu untuk lulus pointer fungsi untuk penyalur dan konstruktor, dll Tujuan dari C ++ template adalah untuk menghindari menulis hampir identik class MyClass_int
, class MyClass_float
, dll, tapi masih bisa berakhir dengan kode dikompilasi yang kebanyakan seolah-olah kami telah menulis setiap versi secara terpisah. Jadi templat secara harfiah templat; templat kelas bukan kelas, itu adalah resep untuk membuat kelas baru untuk setiap yang T
kita temui. Templat tidak dapat dikompilasi menjadi kode, hanya hasil instantiating templat yang dapat dikompilasi.
Jadi ketika foo.cpp dikompilasi, kompiler tidak dapat melihat bar.cpp untuk mengetahui yang MyClass<int>
diperlukan. Ia dapat melihat templat MyClass<T>
, tetapi tidak dapat memancarkan kode untuk itu (ini templat, bukan kelas). Dan ketika bar.cpp dikompilasi, kompiler dapat melihat bahwa ia perlu membuat MyClass<int>
, tetapi ia tidak dapat melihat templat MyClass<T>
(hanya antarmuka di foo.h ) sehingga ia tidak dapat membuatnya.
Jika foo.cpp sendiri menggunakan MyClass<int>
, maka kode untuk itu akan dihasilkan saat kompilasi foo.cpp , jadi ketika bar.o ditautkan ke foo.o mereka dapat dihubungkan dan akan bekerja. Kita dapat menggunakan fakta itu untuk memungkinkan satu set contoh template terbatas untuk diimplementasikan dalam file .cpp dengan menulis satu template. Tetapi tidak ada cara bagi bar.cpp untuk menggunakan templat sebagai templat dan membuat instantiate pada jenis apa pun yang disukainya; hanya dapat menggunakan versi templated sebelumnya dari kelas yang menurut penulis foo.cpp sediakan.
Anda mungkin berpikir bahwa ketika mengkompilasi templat, kompiler harus "menghasilkan semua versi", dengan yang tidak pernah digunakan disaring selama penautan. Selain dari overhead besar dan kesulitan ekstrim pendekatan seperti itu akan dihadapi karena fitur "type modifier" seperti pointer dan array memungkinkan bahkan hanya tipe built-in untuk menimbulkan jumlah jenis yang tak terbatas, apa yang terjadi ketika saya sekarang memperluas program saya dengan menambahkan:
- baz.cpp
- mendeklarasikan dan mengimplementasikan
class BazPrivate
, dan menggunakanMyClass<BazPrivate>
Tidak mungkin ini bisa berhasil kecuali kita juga
- Harus mengkompilasi ulang foo.cpp setiap kali kami mengubah file lain dalam program , seandainya ia menambahkan novel baru instantiation dari
MyClass<T>
- Mengharuskan baz.cpp berisi (mungkin melalui header termasuk) templat lengkap
MyClass<T>
, sehingga kompiler dapat menghasilkan MyClass<BazPrivate>
selama kompilasi baz.cpp .
Tidak ada yang suka (1), karena seluruh program analisis sistem kompilasi mengambil selamanya untuk kompilasi, dan karena itu tidak memungkinkan untuk mendistribusikan dikompilasi perpustakaan tanpa kode sumber. Jadi kita punya (2) sebagai gantinya.