Standar C ++ 17 memperkenalkan "panduan pemotongan template". Saya menyimpulkan itu ada hubungannya dengan pengurangan argumen template baru untuk konstruktor yang diperkenalkan dalam versi standar ini, tetapi saya belum melihat penjelasan sederhana bergaya FAQ tentang apa itu dan untuk apa mereka.
Apa itu panduan pemotongan template di C ++ 17?
Mengapa (dan kapan) kita membutuhkannya?
Bagaimana cara mendeklarasikannya?
Jawaban:
Panduan pemotongan template adalah pola yang terkait dengan kelas template yang memberi tahu compiler cara menerjemahkan sekumpulan argumen konstruktor (dan tipenya) ke dalam parameter template untuk kelas tersebut.
Contoh paling sederhana adalah dari
std::vector
dan konstruktornya yang mengambil pasangan iterator.template<typename Iterator> void func(Iterator first, Iterator last) { vector v(first, last); }
Compiler perlu mencari tahu apa
vector<T>
'sT
jenis akan. Kami tahu jawabannya;T
seharusnyatypename std::iterator_traits<Iterator>::value_type
. Tetapi bagaimana kita memberi tahu kompilator tanpa harus mengetikvector<typename std::iterator_traits<Iterator>::value_type>
?Anda menggunakan panduan pemotongan:
template<typename Iterator> vector(Iterator b, Iterator e) -> vector<typename std::iterator_traits<Iterator>::value_type>;
Ini memberitahu kompiler bahwa, ketika Anda memanggil
vector
konstruktor yang cocok dengan pola itu, ia akan menyimpulkanvector
spesialisasi menggunakan kode di sebelah kanan->
.Anda memerlukan panduan ketika pengurangan tipe dari argumen tidak didasarkan pada tipe dari salah satu argumen tersebut. Menginisialisasi a
vector
dari aninitializer_list
secara eksplisit menggunakanvector
'sT
, jadi tidak memerlukan panduan.Sisi kiri tidak selalu menentukan konstruktor yang sebenarnya. Cara kerjanya adalah, jika Anda menggunakan pengurangan konstruktor template pada sebuah tipe, ia cocok dengan argumen yang Anda berikan terhadap semua panduan deduksi (konstruktor sebenarnya dari template utama menyediakan panduan implisit). Jika ada yang cocok, ia menggunakannya untuk menentukan argumen template mana yang akan diberikan ke tipe.
Tetapi setelah deduksi itu selesai, setelah kompilator menemukan parameter templat untuk tipe tersebut, inisialisasi untuk objek tipe itu berlanjut seolah-olah tidak ada yang terjadi. Artinya, panduan deduksi yang dipilih tidak harus sesuai dengan konstruktor yang dipilih.
Ini juga berarti bahwa Anda dapat menggunakan panduan dengan agregat dan inisialisasi agregat:
template<typename T> struct Thingy { T t; }; Thingy(const char *) -> Thingy<std::string>; Thingy thing{"A String"}; //thing.t is a `std::string`.
Jadi panduan deduksi hanya digunakan untuk mengetahui jenis yang diinisialisasi. Proses sebenarnya dari inisialisasi bekerja persis seperti sebelumnya, setelah penentuan itu dibuat.
sumber
vector v{first, last};
tidak akan melakukan hal yang benar :(std::string{32,'*'}[0] == ' '
(untuk ASCII). Tapi ini semua benar sejak C ++ 11.