C ++ Dasar-dasar Templat: Templat Fungsi

Penafian: artikel dimulai kembali pada bulan Februari, tetapi, untuk alasan yang tergantung pada saya, artikel itu belum selesai. Topiknya sangat luas, sehingga diterbitkan dalam bentuk terpotong. Apa yang tidak cocok akan dipertimbangkan kemudian.



Tidak mungkin untuk memahami C ++ modern tanpa mengetahui apa pola pemrogramannya. Properti bahasa ini membuka kemungkinan luas untuk mengoptimalkan dan menggunakan kembali kode. Pada artikel ini, kami akan mencoba mencari tahu apa itu dan bagaimana semuanya bekerja.

Mekanisme template di C ++ memungkinkan kita untuk memecahkan masalah penyatuan algoritma untuk berbagai jenis: tidak perlu menulis fungsi yang berbeda untuk tipe integer, nyata atau pengguna - cukup untuk menyusun algoritma umum yang tidak tergantung pada tipe data, hanya berdasarkan pada sifat umum. Misalnya, algoritma pengurutan dapat bekerja dengan bilangan bulat serta dengan objek dari tipe "mobil".

Ada templat fungsi dan templat kelas.

Templat fungsi adalah deskripsi umum tentang perilaku fungsi yang dapat dipanggil untuk objek dari tipe yang berbeda. Dengan kata lain, Templat fungsi (fungsi Templat, fungsi umum) adalah keluarga fungsi yang berbeda (atau deskripsi algoritma). Menurut deskripsi, Templat fungsi mirip dengan fungsi biasa: perbedaannya adalah bahwa beberapa elemen tidak didefinisikan (tipe, konstanta) dan parameter.

Template kelas - deskripsi umum dari tipe pengguna di mana atribut dan operasi tipe dapat parameter. Mereka adalah konstruksi dimana kelas nyata dapat dihasilkan dengan mengganti argumen konkret bukan parameter.

Mari kita pertimbangkan templat fungsi secara lebih rinci.

Templat Fungsi


Bagaimana cara menulis fungsi template pertama?


Pertimbangkan kasus penentuan elemen minimum dua. Dalam hal bilangan bulat dan bilangan real, Anda harus menulis 2 fungsi.

int _min(int a, int b){ if( a < b){ return a; } return b; } double _min(double a, double b){ if( a < b){ return a; } return b; } 

Anda tentu saja dapat menerapkan hanya satu fungsi, dengan parameter yang valid, tetapi untuk memahami pola ini akan berbahaya.
Apa yang terjadi jika aplikasi dikompilasi? Kedua implementasi fungsi akan jatuh ke dalam kode biner dari aplikasi, bahkan jika mereka tidak digunakan (namun, sekarang kompiler sangat cerdas, mereka dapat memotong kode yang tidak digunakan). Dan jika Anda perlu menambahkan fungsi yang mendefinisikan minimum 2 baris (sulit untuk membayangkan tanpa menentukan bahwa ada garis minimum) ?!

Dalam hal ini, jika algoritmanya umum untuk jenis yang harus Anda kerjakan, Anda bisa menentukan templat fungsi. Prinsipnya, dalam kasus umum, adalah sebagai berikut:

  1. implementasi fungsi diambil untuk beberapa jenis;
  2. templat tajuk <class Type> (atau templat <typename Type>) ditugaskan, yang berarti bahwa algoritma tersebut menggunakan beberapa jenis Tipe abstrak;
  3. dalam implementasi fungsi, nama tipe diganti dengan Type.

Untuk fungsi min, kita mendapatkan yang berikut:

 template<class Type> Type _min(Type a, Type b){ if( a < b){ return a; } return b; } 

Yang paling menarik adalah kenyataan bahwa sementara tidak ada panggilan ke fungsi min, ketika dikompilasi, itu tidak dibuat dalam kode biner (tidak dipakai ). Dan jika Anda mendeklarasikan sekelompok pemanggilan fungsi dengan variabel dari berbagai tipe, untuk setiap kompiler akan membuat implementasinya sendiri berdasarkan pada templat.

Memanggil fungsi template umumnya sama dengan memanggil fungsi biasa. Dalam hal ini, kompiler akan menentukan tipe mana yang akan digunakan, bukan Tipe, berdasarkan pada tipe parameter aktual. Tetapi jika parameter yang diganti ternyata dari tipe yang berbeda, maka kompiler tidak akan dapat output (instantiate template) implementasi dari template. Jadi, dalam kode berikut, kompiler akan tersandung pada panggilan ketiga, karena tidak dapat menentukan Jenis apa (pikirkan tentang mengapa?):

 #include <iostream> template<class Type> Type _min(Type a, Type b) { if (a < b) { return a; } return b; } int main(int argc, char** argv) { std::cout << _min(1, 2) << std::endl; std::cout << _min(3.1, 1.2) << std::endl; std::cout << _min(5, 2.1) << std::endl; // oops! return 0; } 

Masalah ini diselesaikan dengan menentukan tipe tertentu saat memanggil fungsi.

 #include <iostream> template<class Type> Type _min(Type a, Type b) { if (a < b) { return a; } return b; } int main(int argc, char** argv) { std::cout << _min<double>(5, 2.1) << std::endl; return 0; } 

Kapan fungsi template (tidak) berfungsi?


Pada prinsipnya, Anda dapat memahami bahwa kompiler hanya mengganti tipe yang diinginkan dalam templat. Tetapi apakah fungsi yang dihasilkan selalu fungsional? Jelas tidak. Algoritma apa pun dapat didefinisikan terlepas dari jenis data, tetapi harus menggunakan properti dari data ini. Dalam kasus fungsi template _min, ini merupakan persyaratan untuk mendefinisikan operator pemesanan (operator <).

Setiap templat fungsi mengasumsikan keberadaan properti tertentu dari tipe parameter, tergantung pada implementasinya (misalnya, operator penyalinan, operator pembanding, keberadaan metode tertentu, dll.). Dalam standar bahasa C ++ yang diharapkan, konsep akan bertanggung jawab untuk ini.

Templat fungsi berlebih


Templat fungsi juga bisa kelebihan beban. Biasanya kelebihan ini dilakukan saat

 template<class Type> Type* _min(Type* a, Type* b){ if(*a < *b){ return a; } return b; } 

Kasus khusus


Dalam beberapa kasus, templat fungsi tidak efektif atau salah untuk jenis tertentu. Dalam hal ini, Anda dapat mengkhususkan template, yaitu, menulis implementasi untuk jenis ini. Misalnya, dalam kasus string, Anda mungkin ingin fungsi hanya membandingkan jumlah karakter. Dalam hal spesialisasi Templat fungsi, tipe yang templat ditentukan tidak ditentukan dalam parameter. Berikut ini adalah contoh dari spesialisasi ini.

 template<> std::string _min(std::string a, std::string b){ if(a.size() < b.size()){ return a; } return b; } 

Spesialisasi templat untuk tipe tertentu dilakukan lagi karena alasan ekonomi: jika versi templat fungsi ini tidak digunakan dalam kode, maka itu tidak akan dimasukkan dalam kode biner.
Untuk masa depan, beberapa parameter dan integer tetap ada. Ekstensi alami adalah templat kelas, dasar-dasar pemrograman generatif, dan desain pustaka standar C ++. Dan banyak contoh!

Source: https://habr.com/ru/post/id436880/


All Articles