Gambar 1: template fungsi
TemplHeader.h
template<typename T>
void f();
TemplCpp.cpp
template<typename T>
void f(){
//...
}
//explicit instantation
template void f<T>();
Main.cpp
#include "TemplHeader.h"
extern template void f<T>(); //is this correct?
int main() {
f<char>();
return 0;
}
Apakah ini cara yang benar untuk digunakan extern template
, atau apakah saya menggunakan kata kunci ini hanya untuk templat kelas seperti pada Gambar 2?
Gambar 2: template kelas
TemplHeader.h
template<typename T>
class foo {
T f();
};
TemplCpp.cpp
template<typename T>
void foo<T>::f() {
//...
}
//explicit instantation
template class foo<int>;
Main.cpp
#include "TemplHeader.h"
extern template class foo<int>();
int main() {
foo<int> test;
return 0;
}
Saya tahu itu baik untuk meletakkan semua ini dalam satu file header, tetapi jika kita membuat contoh template dengan parameter yang sama di beberapa file, maka kita mendapat beberapa definisi yang sama dan kompiler akan menghapus semuanya (kecuali satu) untuk menghindari kesalahan. Bagaimana cara saya menggunakan extern template
? Bisakah kita menggunakannya hanya untuk kelas, atau dapatkah kita menggunakannya untuk fungsi juga?
Selain itu, Gambar 1 dan Gambar 2 dapat diperluas menjadi solusi di mana templat berada dalam satu file header. Dalam hal ini, kita perlu menggunakan extern template
kata kunci untuk menghindari beberapa instan yang sama. Apakah ini hanya untuk kelas atau fungsi juga?
extern template class foo<int>();
sepertinya ada kesalahan.()
baris eksternal. baik buku dan studio visual Anda salah, coba gunakan kompiler yang lebih memenuhi standar seperti g ++ atau clang dan Anda akan melihat masalahnya.Jawaban:
Anda sebaiknya hanya menggunakan
extern template
untuk memaksa compiler agar tidak membuat instance template saat Anda mengetahuinya bahwa itu akan dibuat di tempat lain. Ini digunakan untuk mengurangi waktu kompilasi dan ukuran file objek.Sebagai contoh:
Ini akan menghasilkan file objek berikut:
Jika kedua file dihubungkan bersama, salah satunya
void ReallyBigFunction<int>()
akan dibuang, mengakibatkan waktu kompilasi dan ukuran file objek terbuang percuma.Agar tidak menyia-nyiakan waktu kompilasi dan ukuran file objek, ada
extern
kata kunci yang membuat compiler tidak mengkompilasi fungsi template. Anda harus menggunakan ini jika dan hanya jika Anda tahu ini digunakan dalam biner yang sama di tempat lain.Mengubah
source2.cpp
ke:Akan menghasilkan file objek berikut:
Ketika keduanya akan dihubungkan bersama, file objek kedua hanya akan menggunakan simbol dari file objek pertama. Tidak perlu membuang dan tidak membuang waktu kompilasi dan ukuran file objek.
Ini hanya boleh digunakan dalam proyek, seperti saat Anda menggunakan template seperti
vector<int>
beberapa kali, Anda harus menggunakanextern
semua kecuali satu file sumber.Ini juga berlaku untuk kelas dan fungsi sebagai satu, dan bahkan fungsi anggota template.
sumber
Wikipedia memiliki deskripsi terbaik
Peringatan:
nonstandard extension used...
Microsoft VC ++ dulu memiliki versi non-standar dari fitur ini selama beberapa tahun (dalam C ++ 03). Kompilator memperingatkan tentang hal itu untuk mencegah masalah portabilitas dengan kode yang perlu dikompilasi pada kompiler yang berbeda juga.
Lihat contoh di halaman tertaut untuk melihat bahwa cara kerjanya kira-kira sama. Anda dapat mengharapkan pesan untuk pergi dengan versi masa depan dari MSVC, kecuali tentu saja ketika menggunakan lainnya ekstensi compiler non-standar pada waktu yang sama.
sumber
std::vector
(cukup yakin semuanya melakukannya),extern
tidak akan berpengaruh.extern template
hanya diperlukan jika deklarasi template selesaiIni diisyaratkan dalam jawaban lain, tetapi menurut saya tidak cukup penekanan yang diberikan padanya.
Artinya, dalam contoh OP,
extern template
tidak berpengaruh karena definisi templat pada tajuk tidak lengkap:void f();
: hanya deklarasi, tidak ada tubuhclass foo
: mendeklarasikan metodef()
tetapi tidak memiliki definisiJadi saya akan merekomendasikan hanya menghapus
extern template
definisi dalam kasus khusus itu: Anda hanya perlu menambahkannya jika kelas sudah ditentukan sepenuhnya.Sebagai contoh:
TemplHeader.h
TemplCpp.cpp
Main.cpp
kompilasi dan lihat simbol dengan
nm
:keluaran:
dan kemudian dari
man nm
kita melihat ituU
berarti tidak terdefinisi, jadi definisi itu tetap hanyaTemplCpp
seperti yang diinginkan.Semua ini bermuara pada tradeoff dari deklarasi header lengkap:
extern template
di every Includer, yang mungkin akan dilupakan oleh programmer.Contoh lebih lanjut ditampilkan di: Instansiasi template eksplisit - kapan digunakan?
Karena waktu kompilasi sangat penting dalam proyek besar, saya akan sangat merekomendasikan deklarasi template yang tidak lengkap, kecuali pihak eksternal benar-benar perlu menggunakan kembali kode Anda dengan kelas kustom mereka sendiri yang kompleks.
Dan dalam hal ini, pertama-tama saya akan mencoba menggunakan polimorfisme untuk menghindari masalah waktu pembuatan, dan hanya menggunakan templat jika peningkatan kinerja yang nyata dapat dibuat.
Diuji di Ubuntu 18.04.
sumber
Masalah yang diketahui dengan template adalah code bloating, yang merupakan konsekuensi dari pembuatan definisi kelas di setiap modul yang memanggil spesialisasi template kelas. Untuk mencegah hal ini, dimulai dengan C ++ 0x, seseorang dapat menggunakan kata kunci extern di depan spesialisasi template kelas
Instan eksplisit dari kelas template harus terjadi hanya dalam satu unit terjemahan, lebih disukai yang memiliki definisi template (MyClass.cpp)
sumber
Jika Anda telah menggunakan extern untuk fungsi sebelumnya, filosofi yang persis sama diikuti untuk template. jika tidak, pergi ke luar untuk fungsi sederhana dapat membantu. Selain itu, Anda mungkin ingin meletakkan extern di file header dan menyertakan header saat Anda membutuhkannya.
sumber