Apa itu panduan pemotongan template dan kapan kita harus menggunakannya?

89

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?

Tristan Brindle
sumber
Secara khusus, saya tertarik untuk mengetahui apakah panduan deduksi sebenarnya disediakan oleh C ++ 17 STL (misalnya untuk std :: pair atau std :: tuple). Apa daftar lengkap jenis template standar "deducible" pada C ++ 17?
Quuxplusone
Saya tertarik untuk mengetahui apakah ada kompiler yang mendukung ini. Saya mencoba gcc, clang dan vc ++. rextester.com/DHPHC32332 Nevermind, menurut saya ini hanya berfungsi dengan gc ++ 8.1 C ++ 17 dan 2a g ++ -std = c ++ 17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Jean-Simon Brochu

Jawaban:

102

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::vectordan 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>'s Tjenis akan. Kami tahu jawabannya; Tseharusnya typename std::iterator_traits<Iterator>::value_type. Tetapi bagaimana kita memberi tahu kompilator tanpa harus mengetik vector<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 vectorkonstruktor yang cocok dengan pola itu, ia akan menyimpulkan vectorspesialisasi menggunakan kode di sebelah kanan ->.

Anda memerlukan panduan ketika pengurangan tipe dari argumen tidak didasarkan pada tipe dari salah satu argumen tersebut. Menginisialisasi a vectordari an initializer_listsecara eksplisit menggunakan vector's T, 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.

Nicol Bolas
sumber
7
Hmm, saya baru saja terpikir bahwa meskipun dengan pemandu, vector v{first, last};tidak akan melakukan hal yang benar :(
TC
3
@TC… kecuali hal yang benar adalah membuat vektor iterator. Dan std::string{32,'*'}[0] == ' '(untuk ASCII). Tapi ini semua benar sejak C ++ 11.
Arne Vogel
2
apa yang terjadi dengan parameter vektor pengalokasi? apa yang akan terjadi jika parameter vektor pengalokasi tidak memiliki argumen default? (Anda tidak dapat menyimpulkannya dari InputIterator)
gnzlbg
@NicolBolas: Maukah Anda menjelaskan detail tentang bagaimana panduan deduksi implisit dan eksplisit dapat bekerja dalam konteks kelas yang terspesialisasi sebagian atau sepenuhnya (yang konstruktornya jelas tidak perlu memiliki jenis parameter yang cocok dengan template utama)? Sulit untuk menemukan informasi tentang ini melalui pencarian cepat.
pengguna541686
1
@NicolBolas: Begitu. Tidak jelas bagi saya bahwa pertanyaannya adalah tentang panduan deduksi eksplisit sama sekali ... Saya pikir itu membantu jika Anda hanya memasukkan apa yang Anda tulis secara harfiah dalam komentar ini.
pengguna541686