Apakah templat C ++ hanya semacam makro yang dimuliakan?

27

Dari perbandingan yang berbeda antara templat C ++ dan C # / Java generics seperti ini-

/programming/31693/what-are-the-differences-between-generics-in-c-and-java-and-templates-in-c/31929#31929

Saya mendapat persepsi bahwa, template C ++ diimplementasikan oleh beberapa jenis preprocessing (penggantian teks biasa sebelum parsing), bukan kompilasi. Karena tipe yang memeriksa templat C ++ menyerupai makro C. Maksud saya, jika ada beberapa kesalahan, itu adalah kesalahan dari kode yang dihasilkan setelah memproses blok kode templated, bukan dari template itu sendiri. Dengan kata lain, mereka hanyalah sejenis makro versi atas di C.

Kemudian saya menemukan beberapa fakta lain yang mendukung ini-

  • Saya pikir, jika template C ++ diimplementasikan oleh preprocessing, akan ada masalah dengan tautan dinamis (menggunakan .dll). Dan googling cepat mendukung ini.

  • Poin lainnya adalah, konstanta integer dapat dikirimkan sebagai argumen ke template. Dan itu bahkan mendukung semacam rekursi. Tetapi rekursi ini tidak ditemukan dalam kode perakitan / mesin yang dikompilasi. Hal rekursi dikelola dalam waktu kompilasi dengan menghasilkan fungsi untuk setiap panggilan rekursif dan dengan demikian memiliki biner yang lebih besar tetapi lebih cepat dieksekusi.

Meskipun tidak seperti makro C, ia memiliki beberapa kemampuan superior. Tapi bukankah template C ++ diimplementasikan dengan semacam preprocessing? Bagaimana ini diimplementasikan dalam kompiler C ++ yang berbeda?

Gulshan
sumber
19
Nggak. Templat C ++ dikompilasi.
Edward Strange
2
Apa definisi Anda tentang "preprocessing"? Dan dari "kompilasi"? Definisi "preprocessing" yang cukup luas dapat mencakup semua yang dilakukan oleh kompiler; setelah semua, kompiler benar-benar hanya memproses sumber sebelum dieksekusi, bukan?
James McNellis
@James McNellis IMHO jika Anda hanya bisa membedakan preprocessing dari semua hal lain yang dilakukan untuk kompilasi, itu sudah cukup untuk memahami pertanyaan saya. Untuk mengklarifikasi preprocessor- en.wikipedia.org/wiki/Preprocessor#Lexical_preprosesor
Gulshan
6
Jika Anda merujuk pada bentuk preprocessing itu, maka tidak, template C ++ sama sekali bukan hanya semacam makro yang dimuliakan.
James McNellis
1
Bahasa template sebenarnya sudah selesai sehingga mereka lebih dari makro yang ditingkatkan.
davidk01

Jawaban:

9

Templat C ++ adalah semacam makro Lisp (atau bahkan lebih, Skema) yang bodoh. Ini adalah bahasa Turing-lengkap yang mengevaluasi dalam waktu kompilasi, tetapi sangat terbatas karena tidak ada akses dari bahasa itu ke lingkungan C ++ yang mendasarinya. Jadi, ya, templat C ++ dapat dilihat sebagai beberapa bentuk preprocessing, dengan interaksi yang sangat terbatas dengan kode yang dihasilkan.

Logika SK
sumber
2
"Tapi ini sangat terbatas karena tidak ada akses dari bahasa itu ke lingkungan C ++ yang mendasarinya." -- Apa artinya? Saya mencoba menguraikan pernyataan ini, tetapi gagal.
quant_dev
2
Uhm, sebenarnya ... github.com/kmichel/bf0x
Anton Golov
3
@ SK-logic: Selain itu, C ++ 11 adalah C ++, kecuali jika Anda (dengan pedih) memperlakukan versi berbeda dari bahasa yang sama dengan bahasa yang berbeda.
Jon Purdy
3
@ Jon Purdy, C ++ 11 tidak ada (secara resmi) pada saat jawaban ini. Saat ini sebuah contoh akan lebih rumit, seperti mendekomposisi struktur data, menggunakan fungsi perpustakaan, dll.
SK-logic
1
@ SK-logic: Apakah Anda mengetahui implementasi C ++ dengan makro Lisp-like? Saya muak dengan keterbatasan templat. Contoh bahasa sintaksis gaya C ++ dengan sistem makro yang kuat di Haxe: haxe.org/manual/macros . (Tidak membantu saya karena saya menggunakan C ++ untuk tujuannya - pemrograman mikrokontroler 8-bit; ada bahasa yang lebih baik untuk hal lain).
pfalcon
41

Mungkin perbedaan terbesar adalah bahwa makro C diperluas pada fase preprocessing, sebelum kompilasi lain dilakukan, sementara template C ++ adalah bagian dari kompilasi. Ini berarti bahwa template C ++ adalah tipe-aware dan scoped, antara lain, dan bukan substitusi teks sederhana. Mereka dapat dikompilasi ke fungsi nyata, dan karena itu menghindari sebagian besar masalah yang dimiliki makro. Sadar-jenis berarti bahwa mereka dapat bersifat umum atau khusus: misalnya, mudah untuk menyediakan swapfungsi templat, dan mudah untuk menulis spesialisasi yang berfungsi dengan baik bahkan jika objek mengelola memori tumpukan.

Oleh karena itu: templat C ++ tidak preprocessing dalam arti makro yang sama, mereka bukan semacam makro C, dan tidak mungkin untuk menggunakan makro C untuk menduplikasi apa yang dilakukan templat.

Template hidup dalam file header, bukan di perpustakaan yang ditautkan, benar, tetapi jika Anda memasok .dll Anda mungkin juga menyediakan file header untuk digunakan.

David Thornley
sumber
12
Mereka tidak perlu tinggal di file header (itu hanya teknik paling sederhana untuk menggunakannya). Anda dapat mendefinisikannya dalam file sumber dan secara manual memaksa instantiation dari template dalam file sumber (unit kompilasi). Menautkan kemudian akan mengambil instantiations seperti biasa (ini adalah teknik untuk membatasi template ke tipe tertentu dan tidak mengizinkan semua tipe generik).
Martin York
@ Martin: Saya tidak yakin apakah teknik ini (sementara didukung) sebenarnya didukung oleh standar. Kalau tidak, semua kompiler akan sudah exportmenerapkan. Saya tahu ini semacam berfungsi untuk fungsi, tapi saya ragu itu berfungsi untuk kelas: bagaimana Anda tahu ukurannya?
Matthieu M.
@Matthieu M: Ini tidak ada hubungannya dengan kata kunci ekspor. Ini berkaitan dengan instantiasi template "Eksplisit" dan didefinisikan dengan baik dalam standar.
Martin York
2
@ Matthieu M .: Jika kompiler mengetahui tanda tangan suatu fungsi, dan penghubung dapat menemukan implementasi, semuanya keren. Itu berlaku apakah fungsi tersebut adalah fungsi templat atau tidak. Dalam praktiknya, mereka umumnya hidup dalam file header, karena memaksa instantiations tertentu biasanya lebih berhasil daripada nilainya, tetapi Martin benar dalam mencatat alternatifnya.
David Thornley
Saya tahu itu bekerja, pasti, untuk fungsi-fungsi khusus. Namun saya juga cukup yakin, bahwa itu tidak berfungsi untuk kelas, yang merupakan poin saya. Saya pikir ini berfungsi untuk metode dari kelas khusus juga, tetapi tidak tahu apakah ini standar atau tidak.
Matthieu M.
5

Apakah penting penerapannya? Kompiler C ++ awal hanyalah pra-prosesor yang mengumpankan kode ke kompiler ac, itu tidak berarti C ++ hanyalah makro yang dimuliakan.

Template menghapus kebutuhan untuk makro dengan menyediakan cara yang lebih aman, lebih efisien dan dapat disesuaikan (bahkan saya pikir itu bukan kata sebenarnya) untuk mengimplementasikan kode untuk berbagai jenis.

Ada berbagai cara untuk melakukan templating kode jenis di c, tidak ada yang sangat bagus setelah Anda melampaui tipe sederhana.

Martin Beckett
sumber
Saya belum mengatakan tentang C ++ menjadi makro yang dimuliakan. Saya sangat mengagumi C ++. Hanya ingin tahu.
Gulshan
2
@ Gulshan: Tidak, Anda tidak mengatakan apa-apa tentang itu. Namun demikian, begitulah cara kerja kompiler C ++ awal (kecuali bahwa CFront adalah sesuatu dari kompilator bukan hanya preprocessor makro), dan pernyataan Anda tentang templat C ++ hampir sama berlaku untuk C ++ awal itu sendiri.
David Thornley
CFront mengkompilasi C ++ ke C. Garis antara preprosesor dan kompiler didefinisikan dengan jelas: kompiler mencoba memahami inputnya — melalui parsing, bangunan AST, & c — sementara preprosesor tidak — misalnya, hanya menggunakan subtitusi teks atau token.
Jon Purdy
1
Saya pikir apa yang dimaksud oleh David adalah bahwa ada subset yang mendasari C ++ dan bahwa templat dapat dianggap sebagai semacam makro yang digunakan untuk umum program dalam subset ini, yang kemudian dapat dikompilasi sebagai tahap selanjutnya yang terpisah.
Giorgio
5

Ada beberapa perbedaan; misalnya, templat dapat digunakan untuk instantiate fungsi yang berlebihan saat dibutuhkan, sementara dengan makro, Anda harus memperluas makro sekali untuk setiap kemungkinan kelebihan untuk membuatnya terlihat oleh kompiler, sehingga Anda akan berakhir dengan banyak kode yang tidak digunakan.

Perbedaan lainnya adalah bahwa templat menghormati ruang nama.

Simon Richter
sumber
2

IMHO, C ++ templat dan C Macro dimaksudkan untuk menyelesaikan dua masalah yang sama sekali berbeda. Pustaka Template Standar C ++ asli adalah mekanisme untuk memisahkan secara rapi kelas kontainer (array, linked-list, dll.) Dari fungsi generik yang umum diterapkan pada mereka (seperti penyortiran dan penggabungan). Memiliki representasi abstrak dari algoritma dan struktur data yang efisien mengarah pada kode yang lebih ekspresif karena hanya ada sedikit dugaan bagaimana cara terbaik untuk mengimplementasikan fungsi yang bekerja pada bagian data tertentu. Makro C lebih sesuai dengan apa yang biasanya dilihat orang dalam Lisp macro, karena makalah itu menyediakan sarana untuk "memperluas" bahasa dengan kode yang digarisbawahi. Yang keren adalah bahwa C ++ Standard Library memperluas fungsionalitas templat untuk mencakup sebagian besar dari apa yang kita gunakan #define untuk dalam C.

Marc
sumber